diff options
author | Jason Kirtland <jek@discorporate.us> | 2007-10-31 00:28:53 +0000 |
---|---|---|
committer | Jason Kirtland <jek@discorporate.us> | 2007-10-31 00:28:53 +0000 |
commit | c2092c72541cd5fd6dfcc6fe43be931390de6fd0 (patch) | |
tree | 597847cfdb7bce4038be7a7a0ca5a9edf7d92707 | |
parent | 8edda5baf6f07eed4869b7887f4f1b5c0c885d8b (diff) | |
download | sqlalchemy-c2092c72541cd5fd6dfcc6fe43be931390de6fd0.tar.gz |
- Refinements for maxdb's handling of SERIAL and FIXED columns
- Expanded maxdb's set of paren-less functions
-rw-r--r-- | lib/sqlalchemy/databases/maxdb.py | 56 | ||||
-rw-r--r-- | test/dialect/maxdb.py | 165 | ||||
-rw-r--r-- | test/sql/testtypes.py | 15 |
3 files changed, 209 insertions, 27 deletions
diff --git a/lib/sqlalchemy/databases/maxdb.py b/lib/sqlalchemy/databases/maxdb.py index fcf04bec9..de72295b0 100644 --- a/lib/sqlalchemy/databases/maxdb.py +++ b/lib/sqlalchemy/databases/maxdb.py @@ -157,13 +157,21 @@ class MaxSmallInteger(MaxInteger): class MaxNumeric(sqltypes.Numeric): - """The NUMERIC (also FIXED, DECIMAL) data type.""" + """The FIXED (also NUMERIC, DECIMAL) data type.""" + + def __init__(self, precision=None, length=None, **kw): + kw.setdefault('asdecimal', True) + super(MaxNumeric, self).__init__(length=length, precision=precision, + **kw) + + def bind_processor(self, dialect): + return None def get_col_spec(self): if self.length and self.precision: - return 'NUMERIC(%s, %s)' % (self.precision, self.length) - elif self.length: - return 'NUMERIC(%s)' % self.length + return 'FIXED(%s, %s)' % (self.precision, self.length) + elif self.precision: + return 'FIXED(%s)' % self.precision else: return 'INTEGER' @@ -344,20 +352,21 @@ colspecs = { ischema_names = { 'boolean': MaxBoolean, - 'int': MaxInteger, - 'integer': MaxInteger, - 'varchar': MaxString, 'char': MaxChar, 'character': MaxChar, + 'date': MaxDate, 'fixed': MaxNumeric, 'float': MaxFloat, - 'long': MaxText, + 'int': MaxInteger, + 'integer': MaxInteger, 'long binary': MaxBlob, 'long unicode': MaxText, 'long': MaxText, + 'long': MaxText, + 'smallint': MaxSmallInteger, + 'time': MaxTime, 'timestamp': MaxTimestamp, - 'date': MaxDate, - 'time': MaxTime + 'varchar': MaxString, } @@ -586,7 +595,7 @@ class MaxDBDialect(default.DefaultDialect): include_columns = util.Set(include_columns or []) for row in rows: - (name, mode, col_type, encoding, length, precision, + (name, mode, col_type, encoding, length, scale, nullable, constant_def, func_def) = row name = normalize(name) @@ -596,7 +605,12 @@ class MaxDBDialect(default.DefaultDialect): type_args, type_kw = [], {} if col_type == 'FIXED': - type_args = length, precision + type_args = length, scale + # Convert FIXED(10) DEFAULT SERIAL to our Integer + if (scale == 0 and + func_def is not None and func_def.startswith('SERIAL')): + col_type = 'INTEGER' + type_args = length, elif col_type in 'FLOAT': type_args = length, elif col_type in ('CHAR', 'VARCHAR'): @@ -620,10 +634,15 @@ class MaxDBDialect(default.DefaultDialect): if func_def is not None: if func_def.startswith('SERIAL'): - # strip current numbering - col_kw['default'] = schema.PassiveDefault( - sql.text('SERIAL')) - col_kw['autoincrement'] = True + if col_kw['primary_key']: + # No special default- let the standard autoincrement + # support handle SERIAL pk columns. + col_kw['autoincrement'] = True + else: + # strip current numbering + col_kw['default'] = schema.PassiveDefault( + sql.text('SERIAL')) + col_kw['autoincrement'] = True else: col_kw['default'] = schema.PassiveDefault( sql.text(func_def)) @@ -705,8 +724,9 @@ class MaxDBCompiler(compiler.DefaultCompiler): # These functions must be written without parens when called with no # parameters. e.g. 'SELECT DATE FROM DUAL' not 'SELECT DATE() FROM DUAL' bare_functions = util.Set([ - 'CURRENT_SCHEMA', 'DATE', 'TIME', 'TIMESTAMP', 'TIMEZONE', - 'TRANSACTION', 'USER', 'UID', 'USERGROUP', 'UTCDATE']) + 'CURRENT_SCHEMA', 'DATE', 'FALSE', 'SYSDBA', 'TIME', 'TIMESTAMP', + 'TIMEZONE', 'TRANSACTION', 'TRUE', 'USER', 'UID', 'USERGROUP', + 'UTCDATE', 'UTCDIFF']) def default_from(self): return ' FROM DUAL' diff --git a/test/dialect/maxdb.py b/test/dialect/maxdb.py index 551c26b37..336986744 100644 --- a/test/dialect/maxdb.py +++ b/test/dialect/maxdb.py @@ -3,7 +3,8 @@ import testbase import StringIO, sys from sqlalchemy import * -from sqlalchemy import sql +from sqlalchemy import exceptions, sql +from sqlalchemy.util import Decimal from sqlalchemy.databases import maxdb from testlib import * @@ -12,12 +13,166 @@ from testlib import * # - add "Database" test, a quick check for join behavior on different max versions # - full max-specific reflection suite # - datetime tests -# - decimal etc. tests # - the orm/query 'test_has' destabilizes the server- cover here -class BasicTest(AssertMixin): - def test_import(self): - return True +class ReflectionTest(AssertMixin): + """Extra reflection tests.""" + + def _test_decimal(self, tabledef): + """Checks a variety of FIXED usages. + + This is primarily for SERIAL columns, which can be FIXED (scale-less) + or (SMALL)INT. Ensures that FIXED id columns are converted to + integers and that are assignable as such. Also exercises general + decimal assignment and selection behavior. + """ + + meta = MetaData(testbase.db) + try: + if isinstance(tabledef, basestring): + # run textual CREATE TABLE + testbase.db.execute(tabledef) + else: + _t = tabledef.tometadata(meta) + _t.create() + t = Table('dectest', meta, autoload=True) + + vals = [Decimal('2.2'), Decimal('23'), Decimal('2.4'), 25] + cols = ['d1','d2','n1','i1'] + t.insert().execute(dict(zip(cols,vals))) + roundtrip = list(t.select().execute()) + self.assertEquals(roundtrip, [tuple([1] + vals)]) + + t.insert().execute(dict(zip(['id'] + cols, + [2] + list(roundtrip[0][1:])))) + roundtrip2 = list(t.select(order_by=t.c.id).execute()) + self.assertEquals(roundtrip2, [tuple([1] + vals), + tuple([2] + vals)]) + finally: + try: + testbase.db.execute("DROP TABLE dectest") + except exceptions.DatabaseError: + pass + + @testing.supported('maxdb') + def test_decimal_fixed_serial(self): + tabledef = """ + CREATE TABLE dectest ( + id FIXED(10) DEFAULT SERIAL PRIMARY KEY, + d1 FIXED(10,2), + d2 FIXED(12), + n1 NUMERIC(12,2), + i1 INTEGER) + """ + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_decimal_integer_serial(self): + tabledef = """ + CREATE TABLE dectest ( + id INTEGER DEFAULT SERIAL PRIMARY KEY, + d1 DECIMAL(10,2), + d2 DECIMAL(12), + n1 NUMERIC(12,2), + i1 INTEGER) + """ + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_decimal_implicit_serial(self): + tabledef = """ + CREATE TABLE dectest ( + id SERIAL PRIMARY KEY, + d1 FIXED(10,2), + d2 FIXED(12), + n1 NUMERIC(12,2), + i1 INTEGER) + """ + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_decimal_smallint_serial(self): + tabledef = """ + CREATE TABLE dectest ( + id SMALLINT DEFAULT SERIAL PRIMARY KEY, + d1 FIXED(10,2), + d2 FIXED(12), + n1 NUMERIC(12,2), + i1 INTEGER) + """ + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_decimal_sa_types_1(self): + tabledef = Table('dectest', MetaData(), + Column('id', Integer, primary_key=True), + Column('d1', DECIMAL(10, 2)), + Column('d2', DECIMAL(12)), + Column('n1', NUMERIC(12,2)), + Column('i1', Integer)) + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_decimal_sa_types_2(self): + tabledef = Table('dectest', MetaData(), + Column('id', Integer, primary_key=True), + Column('d1', maxdb.MaxNumeric(10, 2)), + Column('d2', maxdb.MaxNumeric(12)), + Column('n1', maxdb.MaxNumeric(12,2)), + Column('i1', Integer)) + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_decimal_sa_types_3(self): + tabledef = Table('dectest', MetaData(), + Column('id', Integer, primary_key=True), + Column('d1', maxdb.MaxNumeric(10, 2)), + Column('d2', maxdb.MaxNumeric), + Column('n1', maxdb.MaxNumeric(12,2)), + Column('i1', Integer)) + return self._test_decimal(tabledef) + + @testing.supported('maxdb') + def test_assorted_type_aliases(self): + """Ensures that aliased types are reflected properly.""" + + meta = MetaData(testbase.db) + try: + testbase.db.execute(""" + CREATE TABLE assorted ( + c1 INT, + c2 BINARY(2), + c3 DEC(4,2), + c4 DEC(4), + c5 DEC, + c6 DOUBLE PRECISION, + c7 NUMERIC(4,2), + c8 NUMERIC(4), + c9 NUMERIC, + c10 REAL(4), + c11 REAL, + c12 CHARACTER(2)) + """) + table = Table('assorted', meta, autoload=True) + expected = [maxdb.MaxInteger, + maxdb.MaxNumeric, + maxdb.MaxNumeric, + maxdb.MaxNumeric, + maxdb.MaxNumeric, + maxdb.MaxFloat, + maxdb.MaxNumeric, + maxdb.MaxNumeric, + maxdb.MaxNumeric, + maxdb.MaxFloat, + maxdb.MaxFloat, + maxdb.MaxChar,] + for i, col in enumerate(table.columns): + self.assert_(isinstance(col.type, expected[i])) + finally: + try: + testbase.db.execute("DROP TABLE assorted") + except exceptions.DatabaseError: + pass class DBAPITest(AssertMixin): """Asserts quirks in the native Python DB-API driver. diff --git a/test/sql/testtypes.py b/test/sql/testtypes.py index 101efb79b..4af96d57f 100644 --- a/test/sql/testtypes.py +++ b/test/sql/testtypes.py @@ -220,12 +220,16 @@ class ColumnsTest(AssertMixin): 'smallint_column': 'smallint_column SMALLINT', 'varchar_column': 'varchar_column VARCHAR(20)', 'numeric_column': 'numeric_column NUMERIC(12, 3)', - 'float_column': 'float_column NUMERIC(25, 2)' + 'float_column': 'float_column FLOAT(25)', } db = testbase.db - if not db.name=='sqlite' and not db.name=='oracle': - expectedResults['float_column'] = 'float_column FLOAT(25)' + if testing.against('sqlite', 'oracle'): + expectedResults['float_column'] = 'float_column NUMERIC(25, 2)' + + if testing.against('maxdb'): + expectedResults['numeric_column'] = ( + expectedResults['numeric_column'].replace('NUMERIC', 'FIXED')) print db.engine.__module__ testTable = Table('testColumns', MetaData(db), @@ -237,7 +241,10 @@ class ColumnsTest(AssertMixin): ) for aCol in testTable.c: - self.assertEquals(expectedResults[aCol.name], db.dialect.schemagenerator(db.dialect, db, None, None).get_column_specification(aCol)) + self.assertEquals( + expectedResults[aCol.name], + db.dialect.schemagenerator(db.dialect, db, None, None).\ + get_column_specification(aCol)) class UnicodeTest(AssertMixin): """tests the Unicode type. also tests the TypeDecorator with instances in the types package.""" |