summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES9
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py17
-rw-r--r--lib/sqlalchemy/schema.py7
-rw-r--r--test/engine/test_metadata.py25
-rw-r--r--test/sql/test_columns.py43
5 files changed, 69 insertions, 32 deletions
diff --git a/CHANGES b/CHANGES
index 5c5f91581..9c22270bf 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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'
+