to int, for DBAPIs such as pymssql that naively call
str() on values.
+ - CheckConstraint will copy its 'initially', 'deferrable',
+ and '_create_rule' attributes within a copy()/tometadata()
+ [ticket:2000]
+
- engine
- The "unicode warning" against non-unicode bind data
is now raised only when the
prepare() won't raise if no transaction is in progress;
this was a regression introduced in 0.6. [ticket:1998]
+ - Threadlocal engine returns itself upon begin(),
+ begin_nested(); engine then implements contextmanager
+ methods to allow the "with" statement. [ticket:2004]
+
- postgresql
- Single element tuple expressions inside an IN clause
parenthesize correctly, also from [ticket:1984]
a backwards compatibility mode SQAlchemy may attempt to use T-SQL
statements that are unable to be parsed by the database server.
+Triggers
+--------
+
+SQLAlchemy by default uses OUTPUT INSERTED to get at newly
+generated primary key values via SEQUENCE columns. MS-SQL does not
+allow the usage of OUTPUT INSERTED on tables that have triggers.
+To disable the usage of OUTPUT INSERTED on a per-table basis,
+specify ``implicit_returning=False`` to each :class:`.Table`
+which has sequences::
+
+ Table('mytable', metadata,
+ Column('id', Integer, primary_key=True),
+ # ...,
+ implicit_returning=False
+ )
+
+Declarative form::
+
+ class MyClass(Base):
+ # ...
+ __table_args__ = {'implicit_returning':False}
+
+
+This option can also be specified enginewide using the
+``implicit_returning=False`` argument on :func:`.create_engine`.
+
Known Issues
------------
be applied to all connections. See
:meth:`~sqlalchemy.engine.base.Connection.execution_options`
+ :param implicit_returning=True: When ``False``, the RETURNING
+ feature of the database, if available, will not be used
+ to fetch newly generated primary key values. This applies
+ to those backends which support RETURNING or a compatible
+ construct, including Postgresql, Firebird, Oracle, Microsoft
+ SQL Server. The default behavior is to use a compatible RETURNING
+ construct when a single-row INSERT statement is emitted with no
+ existing returning() clause in order to fetch newly generated
+ primary key values.
+
:param label_length=None: optional integer value which limits
the size of dynamically generated column labels to that many
characters. If less than 6, labels are generated as
if not hasattr(self._connections, 'trans'):
self._connections.trans = []
self._connections.trans.append(self.contextual_connect().begin_twophase(xid=xid))
+ return self
def begin_nested(self):
if not hasattr(self._connections, 'trans'):
self._connections.trans = []
self._connections.trans.append(self.contextual_connect().begin_nested())
+ return self
def begin(self):
if not hasattr(self._connections, 'trans'):
self._connections.trans = []
self._connections.trans.append(self.contextual_connect().begin())
+ return self
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ if type is None:
+ self.commit()
+ else:
+ self.rollback()
def prepare(self):
if not hasattr(self._connections, 'trans') or \
__visit_name__ = property(__visit_name__)
def copy(self, **kw):
- return CheckConstraint(self.sqltext, name=self.name)
+ return CheckConstraint(self.sqltext,
+ name=self.name,
+ initially=self.initially,
+ deferrable=self.deferrable,
+ _create_rule=self._create_rule)
class ForeignKeyConstraint(Constraint):
"""A table-level FOREIGN KEY constraint.
return util.constructor_copy(self, cls, **kw)
def _coerce_compared_value(self, op, value):
+ """Suggest a type for a 'coerced' Python value in an expression.
+
+ Given an operator and value, gives the type a chance
+ to return a type which the value should be coerced into.
+
+ The default behavior here is conservative; if the right-hand
+ side is already coerced into a SQL type based on its
+ Python type, it is usually left alone.
+
+ End-user functionality extension here should generally be via
+ :class:`.TypeDecorator`, which provides more liberal behavior in that
+ it defaults to coercing the other side of the expression into this
+ type, thus applying special Python conversions above and beyond those
+ needed by the DBAPI to both ides. It also provides the public method
+ :meth:`.TypeDecorator.coerce_compared_value` which is intended for
+ end-user customization of this behavior.
+
+ """
_coerced_type = _type_map.get(type(value), NULLTYPE)
if _coerced_type is NULLTYPE or _coerced_type._type_affinity \
is self._type_affinity:
return self
def _coerce_compared_value(self, op, value):
+ """See :meth:`.TypeEngine._coerce_compared_value` for a description."""
+
return self.coerce_compared_value(op, value)
def copy(self):
# end Py2K
def _coerce_compared_value(self, op, value):
+ """See :meth:`.TypeEngine._coerce_compared_value` for a description."""
+
if isinstance(value, basestring):
return self
else:
return Interval
def _coerce_compared_value(self, op, value):
+ """See :meth:`.TypeEngine._coerce_compared_value` for a description."""
+
return self.impl._coerce_compared_value(op, value)
finally:
external_connection.close()
+ def test_with_interface(self):
+ trans = tlengine.begin()
+ tlengine.execute(users.insert(), user_id=1, user_name='user1')
+ tlengine.execute(users.insert(), user_id=2, user_name='user2')
+ trans.commit()
+
+ trans = tlengine.begin()
+ tlengine.execute(users.insert(), user_id=3, user_name='user3')
+ trans.__exit__(Exception, "fake", None)
+ trans = tlengine.begin()
+ tlengine.execute(users.insert(), user_id=4, user_name='user4')
+ trans.__exit__(None, None, None)
+ eq_(
+ tlengine.execute(users.select().order_by(users.c.user_id)).fetchall(),
+ [
+ (1, 'user1'),
+ (2, 'user2'),
+ (4, 'user4'),
+ ]
+ )
+
def test_commits(self):
connection = tlengine.connect()
assert connection.execute('select count(*) from query_users'
eq_(getattr(fk1c, k), kw[k])
eq_(getattr(fk2c, k), kw[k])
+ def test_check_constraint_copy(self):
+ r = lambda x: x
+ c = CheckConstraint("foo bar",
+ name='name',
+ initially=True,
+ deferrable=True,
+ _create_rule = r)
+ c2 = c.copy()
+ eq_(c2.name, 'name')
+ eq_(str(c2.sqltext), "foo bar")
+ eq_(c2.initially, True)
+ eq_(c2.deferrable, True)
+ assert c2._create_rule is r
+
def test_fk_construct(self):
c1 = Column('foo', Integer)
c2 = Column('bar', Integer)