diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-02-23 22:15:09 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-02-23 22:15:09 +0000 |
commit | 2aa9f5541bbbaf63a9762c78db21292180b17219 (patch) | |
tree | 02e1693e5e44ec98f5b49a9ef840ef628989fc37 | |
parent | 189414fe2999d281ad8b45b89f97a3c56fc5e84b (diff) | |
download | sqlalchemy-2aa9f5541bbbaf63a9762c78db21292180b17219.tar.gz |
- "out" parameters require a type that is supported by
cx_oracle. An error will be raised if no cx_oracle
type can be found.
- Column() requires a type if it has no foreign keys (this is
not new). An error is now raised if a Column() has no type
and no foreign keys. [ticket:1705]
-rw-r--r-- | CHANGES | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/oracle/cx_oracle.py | 17 | ||||
-rw-r--r-- | lib/sqlalchemy/schema.py | 7 | ||||
-rw-r--r-- | test/engine/test_metadata.py | 25 | ||||
-rw-r--r-- | test/sql/test_columns.py | 43 |
5 files changed, 69 insertions, 32 deletions
@@ -160,6 +160,10 @@ CHANGES VALUES clause of an update/insert generates a compile error. This reduces call counts and eliminates some cases where undesirable name conflicts could still occur. + + - Column() requires a type if it has no foreign keys (this is + not new). An error is now raised if a Column() has no type + and no foreign keys. [ticket:1705] - engines - Added an optional C extension to speed up the sql layer by @@ -207,6 +211,11 @@ CHANGES - Removed the text_as_varchar option. +- oracle + - "out" parameters require a type that is supported by + cx_oracle. An error will be raised if no cx_oracle + type can be found. + - sqlite - Added "native_datetime=True" flag to create_engine(). This will cause the DATE and TIMESTAMP types to skip diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py index cfa5ba45b..854eb875a 100644 --- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py @@ -74,10 +74,11 @@ with this feature but it should be regarded as experimental. """ -from sqlalchemy.dialects.oracle.base import OracleCompiler, OracleDialect, RESERVED_WORDS, OracleExecutionContext +from sqlalchemy.dialects.oracle.base import OracleCompiler, OracleDialect, \ + RESERVED_WORDS, OracleExecutionContext from sqlalchemy.dialects.oracle import base as oracle from sqlalchemy.engine import base -from sqlalchemy import types as sqltypes, util +from sqlalchemy import types as sqltypes, util, exc from datetime import datetime import random @@ -219,11 +220,19 @@ class Oracle_cx_oracleExecutionContext(OracleExecutionContext): name = self.compiled.bind_names[bindparam] value = self.compiled_parameters[0][name] if bindparam.isoutparam: - dbtype = bindparam.type.dialect_impl(self.dialect).get_dbapi_type(self.dialect.dbapi) + dbtype = bindparam.type.dialect_impl(self.dialect).\ + get_dbapi_type(self.dialect.dbapi) if not hasattr(self, 'out_parameters'): self.out_parameters = {} + if dbtype is None: + raise exc.InvalidRequestError("Cannot create out parameter for parameter " + "%r - it's type %r is not supported by" + " cx_oracle" % + (name, bindparam.type) + ) self.out_parameters[name] = self.cursor.var(dbtype) - self.parameters[0][quoted_bind_names.get(name, name)] = self.out_parameters[name] + self.parameters[0][quoted_bind_names.get(name, name)] = \ + self.out_parameters[name] def create_cursor(self): c = self._connection.connection.cursor() diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index c68d1f135..80c03bbba 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -636,7 +636,9 @@ class Column(SchemaItem, expression.ColumnClause): raise exc.ArgumentError( "May not pass type_ positionally and as a keyword.") type_ = args.pop(0) - + + no_type = type_ is None + super(Column, self).__init__(name, None, type_) self.key = kwargs.pop('key', name) self.primary_key = kwargs.pop('primary_key', False) @@ -686,6 +688,9 @@ class Column(SchemaItem, expression.ColumnClause): for_update=True)) self._init_items(*args) + if not self.foreign_keys and no_type: + raise exc.ArgumentError("'type' is required on Column objects " + "which have no foreign keys.") util.set_creation_order(self) if 'info' in kwargs: diff --git a/test/engine/test_metadata.py b/test/engine/test_metadata.py index 2fadfe272..50109e15a 100644 --- a/test/engine/test_metadata.py +++ b/test/engine/test_metadata.py @@ -4,7 +4,7 @@ from sqlalchemy import Integer, String, UniqueConstraint, CheckConstraint,\ ForeignKey, MetaData, Sequence, ForeignKeyConstraint,\ ColumnDefault from sqlalchemy.test.schema import Table, Column -from sqlalchemy import schema +from sqlalchemy import schema, exc import sqlalchemy as tsa from sqlalchemy.test import TestBase, ComparesTables, AssertsCompiledSQL, testing, engines from sqlalchemy.test.testing import eq_ @@ -242,26 +242,3 @@ class TableOptionsTest(TestBase, AssertsCompiledSQL): t.info['bar'] = 'zip' assert t.info['bar'] == 'zip' -class ColumnOptionsTest(TestBase): - - def test_default_generators(self): - g1, g2 = Sequence('foo_id_seq'), ColumnDefault('f5') - assert Column(default=g1).default is g1 - assert Column(onupdate=g1).onupdate is g1 - assert Column(default=g2).default is g2 - assert Column(onupdate=g2).onupdate is g2 - - - def test_column_info(self): - - c1 = Column('foo', info={'x':'y'}) - c2 = Column('bar', info={}) - c3 = Column('bat') - assert c1.info == {'x':'y'} - assert c2.info == {} - assert c3.info == {} - - for c in (c1, c2, c3): - c.info['bar'] = 'zip' - assert c.info['bar'] == 'zip' - diff --git a/test/sql/test_columns.py b/test/sql/test_columns.py index e9dabe142..3cbb01943 100644 --- a/test/sql/test_columns.py +++ b/test/sql/test_columns.py @@ -11,11 +11,11 @@ class ColumnDefinitionTest(TestBase): # flesh this out with explicit coverage... def columns(self): - return [ Column(), - Column('b'), + return [ Column(Integer), + Column('b', Integer), Column(Integer), Column('d', Integer), - Column(name='e'), + Column(Integer, name='e'), Column(type_=Integer), Column(Integer()), Column('h', Integer()), @@ -56,3 +56,40 @@ class ColumnDefinitionTest(TestBase): assert_raises(exc.ArgumentError, Column, 'foo', Integer, type_=Integer()) + +class ColumnOptionsTest(TestBase): + + def test_default_generators(self): + g1, g2 = Sequence('foo_id_seq'), ColumnDefault('f5') + assert Column(String, default=g1).default is g1 + assert Column(String, onupdate=g1).onupdate is g1 + assert Column(String, default=g2).default is g2 + assert Column(String, onupdate=g2).onupdate is g2 + + def test_type_required(self): + assert_raises(exc.ArgumentError, Column) + assert_raises(exc.ArgumentError, Column, "foo") + assert_raises(exc.ArgumentError, Column, default="foo") + assert_raises(exc.ArgumentError, Column, Sequence("a")) + assert_raises(exc.ArgumentError, Column, "foo", default="foo") + assert_raises(exc.ArgumentError, Column, "foo", Sequence("a")) + Column(ForeignKey('bar.id')) + Column("foo", ForeignKey('bar.id')) + Column(ForeignKey('bar.id'), default="foo") + Column(ForeignKey('bar.id'), Sequence("a")) + Column("foo", ForeignKey('bar.id'), default="foo") + Column("foo", ForeignKey('bar.id'), Sequence("a")) + + def test_column_info(self): + + c1 = Column('foo', String, info={'x':'y'}) + c2 = Column('bar', String, info={}) + c3 = Column('bat', String) + assert c1.info == {'x':'y'} + assert c2.info == {} + assert c3.info == {} + + for c in (c1, c2, c3): + c.info['bar'] = 'zip' + assert c.info['bar'] == 'zip' + |