Update of /cvsroot/sqlobject/SQLObject/SQLObject
In directory sc8-pr-cvs1:/tmp/cvs-serv22180/SQLObject
Modified Files:
Col.py DBConnection.py
Log Message:
Added Firebird support. Untested! Need to figure out how to set
up Firebird on my computer...
Index: Col.py
===================================================================
RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Col.py,v
retrieving revision 1.24
retrieving revision 1.25
diff -C2 -d -r1.24 -r1.25
*** Col.py 28 Jun 2003 22:21:21 -0000 1.24
--- Col.py 6 Sep 2003 02:33:17 -0000 1.25
***************
*** 162,165 ****
--- 162,169 ----
return ''
+ def _firebirdType(self):
+ return self._sqlType()
+
+
def mysqlCreateSQL(self):
return ' '.join([self.dbName, self._mysqlType()] + self._extraSQL())
***************
*** 171,174 ****
--- 175,181 ----
return ' '.join([self.dbName, self._sqliteType()] + self._extraSQL())
+ def firebirdCreateSQL(self):
+ return ' '.join([self.dbName, self._firebirdType()] + self._extraSQL())
+
class Col(object):
***************
*** 258,261 ****
--- 265,271 ----
def _postgresType(self):
+ return 'INT'
+
+ def _firebirdType(self):
return 'INT'
Index: DBConnection.py
===================================================================
RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/DBConnection.py,v
retrieving revision 1.41
retrieving revision 1.42
diff -C2 -d -r1.41 -r1.42
*** DBConnection.py 18 Jul 2003 03:15:50 -0000 1.41
--- DBConnection.py 6 Sep 2003 02:33:17 -0000 1.42
***************
*** 29,32 ****
--- 29,38 ----
except ImportError:
sqlite = None
+
+ try:
+ import kinterbasdb
+ except ImportError:
+ kinterbasdb = None
+
import re
import warnings
***************
*** 36,40 ****
__all__ = ['MySQLConnection', 'PostgresConnection', 'SQLiteConnection',
! 'DBMConnection']
_connections = {}
--- 42,46 ----
__all__ = ['MySQLConnection', 'PostgresConnection', 'SQLiteConnection',
! 'DBMConnection', 'FirebirdConnection']
_connections = {}
***************
*** 605,608 ****
--- 611,772 ----
# turn it into a boolean:
return not not result
+
+ ########################################
+ ## Firebird connection
+ ########################################
+
+ class FirebirdConnection(DBAPI):
+
+ def __init__(self, host, db, user='sysdba',
+ passwd='masterkey', autoCommit=1, **kw):
+ assert kinterbasdb, 'kinterbasdb module cannot be found'
+
+ self.limit_re = re.compile('^\s*(select )(.*)', re.IGNORECASE)
+
+ if not autoCommit and not kw.has_key('pool'):
+ # Pooling doesn't work with transactions...
+ kw['pool'] = 0
+
+ self.host = host
+ self.db = db
+ self.user = user
+ self.passwd = passwd
+
+ DBAPI.__init__(self, **kw)
+
+ def makeConnection(self):
+ return kinterbasdb.connect(
+ host = self.host, database = self.db,
+ user = self.user, password = self.passwd
+ )
+
+ def _queryInsertID(self, conn, table, idName, names, values):
+ """Firebird uses 'generators' to create new ids for a table.
+ The users needs to create a generator named GEN_<tablename>
+ for each table this method to work."""
+
+ row = self.queryOne('SELECT gen_id(GEN_%s,1) FROM rdb$database'
+ % table)
+ new_key = row[0]
+ names.append('ID')
+ values.append(new_key)
+ qry = self._insertSQL(table, names, values)
+ if self.debug:
+ print 'QueryIns: %s' % q
+ self.query(qry)
+ return new_key
+
+ def _queryAddLimitOffset(self, query, start, end):
+ """Firebird slaps the limit and offset (actually 'first' and
+ 'skip', respectively) statement right after the select."""
+ if not start:
+ limit_str = "SELECT FIRST %i" % end
+ if not end:
+ limit_str = "SELECT SKIP %i" % start
+ else:
+ limit_str = "SELECT FIRST %i SKIP %i" % (end-start, start)
+
+ match = self.limit_re.match(query)
+ if self.debug:
+ print query
+ if match and len(match.groups()) == 2:
+ return ' '.join([limit_str, match.group(1)])
+ else:
+ return query
+
+ def createTable(self, soClass):
+ self.query('CREATE TABLE %s (\n%s\n)' % \
+ (soClass._table, self.createColumns(soClass)))
+ self.query("CREATE GENERATOR GEN_%s" % soClass._table)
+
+ def createColumn(self, soClass, col):
+ return col.firebirdCreateSQL()
+
+ def createIDColumn(self, soClass):
+ return '%s INT NOT NULL PRIMARY KEY' % soClass._idName
+
+ def joinSQLType(self, join):
+ return 'INT NOT NULL'
+
+ def tableExists(self, tableName):
+ # there's something in the database by this name...let's
+ # assume it's a table. By default, fb 1.0 stores EVERYTHING
+ # it cares about in uppercase.
+ result = self.queryOne("SELECT COUNT(rdb$relation_name) FROM rdb$relations WHERE rdb$relation_name = '%s'"
+ % tableName.upper())
+ return result[0]
+
+ def addColumn(self, tableName, column):
+ self.query('ALTER TABLE %s ADD COLUMN %s' %
+ (tableName,
+ column.firebirdCreateSQL()))
+
+ def dropTable(self, tableName):
+ self.query("DROP TABLE %s" % tableName)
+ self.query("DROP GENERATOR GEN_%s" % tableName)
+
+ def delColumn(self, tableName, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' %
+ (tableName,
+ column.dbName))
+
+ def columnsFromSchema(self, tableName, soClass):
+ #let's punt for now!!!
+ return
+ keyQuery = """
+ SELECT pg_catalog.pg_get_constraintdef(oid) as condef
+ FROM pg_catalog.pg_constraint r
+ WHERE r.conrelid = '%s'::regclass AND r.contype = 'f'"""
+
+ colQuery = """
+ SELECT a.attname,
+ pg_catalog.format_type(a.atttypid, a.atttypmod), a.attnotnull,
+ (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d
+ WHERE d.adrelid=a.attrelid AND d.adnum = a.attnum)
+ FROM pg_catalog.pg_attribute a
+ WHERE a.attrelid ='%s'::regclass
+ AND a.attnum > 0 AND NOT a.attisdropped
+ ORDER BY a.attnum"""
+
+ keyData = self.queryAll(keyQuery % tableName)
+ keyRE = re.compile("\((.+)\) REFERENCES (.+)\(")
+ keymap = {}
+ for (condef,) in keyData:
+ match = keyRE.search(condef)
+ if match:
+ field, reftable = match.groups()
+ keymap[field] = reftable.capitalize()
+ colData = self.queryAll(colQuery % tableName)
+ results = []
+ for field, t, notnull, defaultstr in colData:
+ if field == 'id':
+ continue
+ colClass, kw = self.guessClass(t)
+ kw['name'] = soClass._style.dbColumnToPythonAttr(field)
+ kw['notNone'] = notnull
+ if defaultstr is not None:
+ kw['default'] = getattr(SQLBuilder.const, defaultstr)
+ if keymap.has_key(field):
+ kw['foreignKey'] = keymap[field]
+ results.append(colClass(**kw))
+ return results
+
+ def guessClass(self, t):
+ # ditto on the punting
+ return
+ if t.count('int'):
+ return Col.IntCol, {}
+ elif t.count('varying'):
+ return Col.StringCol, {'length': int(t[t.index('(')+1:-1])}
+ elif t.startswith('character('):
+ return Col.StringCol, {'length': int(t[t.index('(')+1:-1]),
+ 'varchar': False}
+ elif t=='text':
+ return Col.StringCol, {}
+ elif t.startswith('datetime'):
+ return Col.DateTimeCol, {}
+ else:
+ return Col.Col, {}
+
########################################
|