Author: phd
Date: 2006-12-28 13:12:10 -0700 (Thu, 28 Dec 2006)
New Revision: 2157
Modified:
home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py
home/phd/SQLObject/paramstyles/sqlobject/main.py
home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py
home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py
home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py
home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py
home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py
home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py
Log:
Merged patches from the revisions 2153:2156 from the trunk
Modified: home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/firebird/firebirdconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -161,10 +161,8 @@
self.query("DROP TABLE %s" % tableName)
self.query("DROP GENERATOR GEN_%s" % tableName)
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
"""
Modified: home/phd/SQLObject/paramstyles/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/main.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/main.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -493,7 +493,7 @@
if changeSchema:
conn = connection or soClass._connection
- conn.delColumn(sqlmeta.table, column)
+ conn.delColumn(sqlmeta, column)
if soClass._SO_finishedClassCreation:
unmakeProperties(soClass)
Modified: home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/maxdb/maxdbconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -211,10 +211,8 @@
(tableName,
column.maxdbCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
GET_COLUMNS = """
SELECT COLUMN_NAME, NULLABLE, DATA_DEFAULT, DATA_TYPE,
Modified: home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/mssql/mssqlconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -181,10 +181,8 @@
(tableName,
column.mssqlCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (tableName.table, column.dbName))
# precision and scale is gotten from column table so that we can create
# decimal columns if needed
Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -177,10 +177,8 @@
(tableName,
column.mysqlCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
colData = self.queryAll("SHOW COLUMNS FROM %s"
Modified: home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/postgres/pgconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -177,10 +177,8 @@
(tableName,
column.postgresCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
def columnsFromSchema(self, tableName, soClass):
Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -1,5 +1,6 @@
from sqlobject.dbconnection import DBAPI
from sqlobject.col import popKey
+from sqlobject import col, sqlbuilder
from sqlobject.dberrors import *
import thread
@@ -88,6 +89,7 @@
# use only one connection for sqlite - supports multiple)
# cursors per connection
self._connOptions = opts
+ self.use_table_info = popKey(kw, "use_table_info", False)
DBAPI.__init__(self, **kw)
self._threadPool = {}
self._threadOrigination = {}
@@ -241,9 +243,12 @@
return None
def createIDColumn(self, soClass):
- key_type = {int: "INTEGER", str: "TEXT"}[soClass.sqlmeta.idType]
- return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type)
+ return self._createIDColumn(soClass.sqlmeta)
+ def _createIDColumn(self, sqlmeta):
+ key_type = {int: "INTEGER", str: "TEXT"}[sqlmeta.idType]
+ return '%s %s PRIMARY KEY' % (sqlmeta.idName, key_type)
+
def joinSQLType(self, join):
return 'INT NOT NULL'
@@ -259,9 +264,98 @@
self.query('ALTER TABLE %s ADD COLUMN %s' %
(tableName,
column.sqliteCreateSQL()))
+ self.query('VACUUM %s' % tableName)
- def delColumn(self, tableName, column):
- pass # Oops! There is no DROP COLUMN in SQLite
+ def delColumn(self, sqlmeta, column):
+ self.recreateTableWithoutColumn(sqlmeta, column)
+ def recreateTableWithoutColumn(self, sqlmeta, column):
+ new_name = sqlmeta.table + '_ORIGINAL'
+ self.query('ALTER TABLE %s RENAME TO %s' % (sqlmeta.table, new_name))
+ cols = [self._createIDColumn(sqlmeta)] \
+ + [self.createColumn(None, col)
+ for col in sqlmeta.columnList if col.name != column.name]
+ cols = ",\n".join([" %s" % c for c in cols])
+ self.query('CREATE TABLE %s (\n%s\n)' % (sqlmeta.table, cols))
+ all_columns = ', '.join(['id'] + [col.dbName for col in sqlmeta.columnList])
+ self.query('INSERT INTO %s (%s) SELECT %s FROM %s' % (
+ sqlmeta.table, all_columns, all_columns, new_name))
+ self.query('DROP TABLE %s' % new_name)
+
+ def columnsFromSchema(self, tableName, soClass):
+ if self.use_table_info:
+ return self._columnsFromSchemaTableInfo(tableName, soClass)
+ else:
+ return self._columnsFromSchemaParse(tableName, soClass)
+
+ def _columnsFromSchemaTableInfo(self, tableName, soClass):
+ colData = self.queryAll("PRAGMA table_info(%s)" % tableName)
+ results = []
+ for index, field, t, nullAllowed, default, key in colData:
+ if field == 'id':
+ continue
+ colClass, kw = self.guessClass(t)
+ kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
+ kw['dbName'] = field
+ kw['notNone'] = not nullAllowed
+ kw['default'] = default
+ # @@ skip key...
+ # @@ skip extra...
+ results.append(colClass(**kw))
+ return results
+
+ def _columnsFromSchemaParse(self, tableName, soClass):
+ colData = self.queryOne("SELECT sql FROM sqlite_master WHERE type='table' AND name='%s'"
+ % tableName)
+ if not colData:
+ raise ValueError('The table %s ws not found in the database. Load failed.' % tableName)
+ colData = colData[0].split('(', 1)[1].strip()[:-2]
+ while colData.find('(') > -1:
+ st = colData.find('(')
+ en = colData.find(')')
+ colData = colData[:st] + colData[en+1:]
+ results = []
+ for colDesc in colData.split(','):
+ parts = colDesc.strip().split(' ', 2)
+ field = parts[0].strip()
+ # skip comments
+ if field.startswith('--'):
+ continue
+ # get rid of enclosing quotes
+ if field[0] == field[-1] == '"':
+ field = field[1:-1]
+ if field == getattr(soClass.sqlmeta, 'idName', 'id'):
+ continue
+ colClass, kw = self.guessClass(parts[1].strip())
+ if len(parts) == 2:
+ index_info = ''
+ else:
+ index_info = parts[2].strip().upper()
+ kw['name'] = soClass.sqlmeta.style.dbColumnToPythonAttr(field)
+ import re
+ nullble = re.search(r'(\b\S*)\sNULL', index_info)
+ default = re.search(r"DEFAULT\s((?:\d[\dA-FX.]*)|(?:'[^']*')|(?:#[^#]*#))", index_info)
+ kw['notNone'] = nullble and nullble.group(1) == 'NOT'
+ kw['default'] = default and default.group(1)
+ # @@ skip key...
+ # @@ skip extra...
+ results.append(colClass(**kw))
+ return results
+
+ def guessClass(self, t):
+ t = t.upper()
+ if t.find('INT') > 0:
+ return col.IntCol, {}
+ elif t.find('TEXT') > 0 or t.find('CHAR') > 0 or t.find('CLOB') > 0:
+ return col.StringCol, {'length': 2**32-1}
+ elif t.find('BLOB') > 0:
+ return col.BLOBCol, {"length": 2**32-1}
+ elif t.find('REAL') > 0 or t.find('FLOAT') > 0:
+ return col.FloatCol, {}
+ elif t.find('DECIMAL') > 0:
+ return col.DecimalCol, {}
+ else:
+ return col.Col, {}
+
def stop_pysqlite2_converting_strings(s):
return s
Modified: home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/sybase/sybaseconnection.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -128,10 +128,8 @@
(tableName,
column.sybaseCreateSQL()))
- def delColumn(self, tableName, column):
- self.query('ALTER TABLE %s DROP COLUMN %s' %
- (tableName,
- column.dbName))
+ def delColumn(self, sqlmeta, column):
+ self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table, column.dbName))
SHOW_COLUMNS=('SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS '
'WHERE TABLE_NAME = \'%s\'')
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -36,7 +36,6 @@
'+exceptions': 'mysql sqlite',
'-transactions': 'mysql',
'-dropTableCascade': 'sybase mssql',
- '-fromDatabase': 'sqlite',
'-expressionIndex': 'mysql sqlite firebird mssql',
'-blobData': 'mssql',
'-decimalColumn': 'mssql',
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -107,6 +107,19 @@
)
"""
+ sqliteCreate = """
+ CREATE TABLE auto_test (
+ auto_id INTEGER PRIMARY KEY AUTOINCREMENT ,
+ first_name VARCHAR(100),
+ last_name VARCHAR(200) NOT NULL,
+ age INT DEFAULT NULL,
+ created DATETIME NOT NULL,
+ happy char(1) DEFAULT 'Y' NOT NULL,
+ long_field TEXT,
+ wannahavefun INT DEFAULT 0 NOT NULL
+ )
+ """
+
sybaseCreate = """
CREATE TABLE auto_test (
auto_id integer,
@@ -141,12 +154,8 @@
DROP TABLE auto_test
"""
- sybaseDrop = """
- DROP TABLE auto_test
- """
+ sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop
- mssqlDrop = sybaseDrop
-
def setup_method(self, meth):
conn = getConnection()
dbName = conn.dbName
@@ -162,8 +171,6 @@
conn.query(dropper)
def test_classCreate(self):
- if not supports('fromDatabase'):
- return
class AutoTest(SQLObject):
_connection = getConnection()
class sqlmeta(sqlmeta):
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py 2006-12-28 20:10:21 UTC (rev 2156)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_auto_old.py 2006-12-28 20:12:10 UTC (rev 2157)
@@ -96,6 +96,19 @@
)
"""
+ sqliteCreate = """
+ CREATE TABLE old_auto_test (
+ auto_id INTEGER PRIMARY KEY AUTOINCREMENT ,
+ first_name VARCHAR(100),
+ last_name VARCHAR(200) NOT NULL,
+ age INT DEFAULT NULL,
+ created DATETIME NOT NULL,
+ happy char(1) DEFAULT 'Y' NOT NULL,
+ long_field TEXT,
+ wannahavefun INT DEFAULT 0 NOT NULL
+ )
+ """
+
sybaseCreate = """
CREATE TABLE old_auto_test (
auto_id integer,
@@ -129,13 +142,8 @@
DROP TABLE old_auto_test
"""
- sybaseDrop = """
- DROP TABLE old_auto_test
- """
+ sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop
- mssqlDrop = """
- DROP TABLE old_auto_test
- """
def setup_method(self, meth):
conn = getConnection()
dbName = conn.dbName
@@ -151,8 +159,6 @@
conn.query(dropper)
def test_classCreate(self):
- if not supports('fromDatabase'):
- return
class OldAutoTest(SQLObject):
_connection = getConnection()
class sqlmeta(sqlmeta):
|