mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-18 14:42:01 -04:00
- added "autocommit=True" kwarg to select() and text(),
as well as generative autocommit() method on select(); for statements which modify the database through some user-defined means other than the usual INSERT/UPDATE/ DELETE etc., this flag will enable "autocommit" behavior during execution if no transaction is in progress [ticket:915]
This commit is contained in:
@@ -16,6 +16,14 @@ CHANGES
|
||||
|
||||
- cast() accepts text('something') and other non-literal
|
||||
operands properly [ticket:962]
|
||||
|
||||
- added "autocommit=True" kwarg to select() and text(),
|
||||
as well as generative autocommit() method on select();
|
||||
for statements which modify the database through some
|
||||
user-defined means other than the usual INSERT/UPDATE/
|
||||
DELETE etc., this flag will enable "autocommit" behavior
|
||||
during execution if no transaction is in progress
|
||||
[ticket:915]
|
||||
|
||||
- The '.c.' attribute on a selectable now gets an entry
|
||||
for every column expression in its columns clause.
|
||||
|
||||
@@ -164,10 +164,10 @@ class DefaultExecutionContext(base.ExecutionContext):
|
||||
self.isupdate = compiled.isupdate
|
||||
if isinstance(compiled.statement, expression._TextClause):
|
||||
self.returns_rows = self.returns_rows_text(self.statement)
|
||||
self.should_autocommit = self.should_autocommit_text(self.statement)
|
||||
self.should_autocommit = compiled.statement._autocommit or self.should_autocommit_text(self.statement)
|
||||
else:
|
||||
self.returns_rows = self.returns_rows_compiled(compiled)
|
||||
self.should_autocommit = self.should_autocommit_compiled(compiled)
|
||||
self.should_autocommit = getattr(compiled.statement, '_autocommit', False) or self.should_autocommit_compiled(compiled)
|
||||
|
||||
if not parameters:
|
||||
self.compiled_parameters = [compiled.construct_params()]
|
||||
|
||||
@@ -158,6 +158,11 @@ def select(columns=None, whereclause=None, from_obj=[], **kwargs):
|
||||
\**kwargs
|
||||
Additional parameters include:
|
||||
|
||||
autocommit
|
||||
indicates this SELECT statement modifies the database, and
|
||||
should be subject to autocommit behavior if no transaction
|
||||
has been started.
|
||||
|
||||
prefixes
|
||||
a list of strings or ``ClauseElement`` objects to include
|
||||
directly after the SELECT keyword in the generated statement,
|
||||
@@ -727,6 +732,11 @@ def text(text, bind=None, *args, **kwargs):
|
||||
bind
|
||||
an optional connection or engine to be used for this text query.
|
||||
|
||||
autocommit=True
|
||||
indicates this SELECT statement modifies the database, and
|
||||
should be subject to autocommit behavior if no transaction
|
||||
has been started.
|
||||
|
||||
bindparams
|
||||
a list of ``bindparam()`` instances which can be used to define
|
||||
the types and/or initial values for the bind parameters within
|
||||
@@ -740,6 +750,7 @@ def text(text, bind=None, *args, **kwargs):
|
||||
which will be used to perform post-processing on columns within
|
||||
the result set (for textual statements that produce result
|
||||
sets).
|
||||
|
||||
"""
|
||||
|
||||
return _TextClause(text, bind=bind, *args, **kwargs)
|
||||
@@ -1821,10 +1832,11 @@ class _TextClause(ClauseElement):
|
||||
|
||||
_bind_params_regex = re.compile(r'(?<![:\w\x5c]):(\w+)(?!:)', re.UNICODE)
|
||||
|
||||
def __init__(self, text = "", bind=None, bindparams=None, typemap=None):
|
||||
def __init__(self, text = "", bind=None, bindparams=None, typemap=None, autocommit=False):
|
||||
self._bind = bind
|
||||
self.bindparams = {}
|
||||
self.typemap = typemap
|
||||
self._autocommit = autocommit
|
||||
if typemap is not None:
|
||||
for key in typemap.keys():
|
||||
typemap[key] = sqltypes.to_instance(typemap[key])
|
||||
@@ -2711,9 +2723,10 @@ class TableClause(FromClause):
|
||||
class _SelectBaseMixin(object):
|
||||
"""Base class for ``Select`` and ``CompoundSelects``."""
|
||||
|
||||
def __init__(self, use_labels=False, for_update=False, limit=None, offset=None, order_by=None, group_by=None, bind=None):
|
||||
def __init__(self, use_labels=False, for_update=False, limit=None, offset=None, order_by=None, group_by=None, bind=None, autocommit=False):
|
||||
self.use_labels = use_labels
|
||||
self.for_update = for_update
|
||||
self._autocommit = autocommit
|
||||
self._limit = limit
|
||||
self._offset = offset
|
||||
self._bind = bind
|
||||
@@ -2734,7 +2747,7 @@ class _SelectBaseMixin(object):
|
||||
return _ScalarSelect(self)
|
||||
|
||||
def apply_labels(self):
|
||||
"""set the 'labels' flag on this selectable.
|
||||
"""return a new selectable with the 'use_labels' flag set to True.
|
||||
|
||||
This will result in column expressions being generated using labels against their table
|
||||
name, such as "SELECT somecolumn AS tablename_somecolumn". This allows selectables which
|
||||
@@ -2760,6 +2773,13 @@ class _SelectBaseMixin(object):
|
||||
|
||||
return True
|
||||
|
||||
def autocommit(self):
|
||||
"""return a new selectable with the 'autocommit' flag set to True."""
|
||||
|
||||
s = self._generate()
|
||||
s._autocommit = True
|
||||
return s
|
||||
|
||||
def _generate(self):
|
||||
s = self._clone()
|
||||
s._clone_from_clause()
|
||||
|
||||
@@ -375,6 +375,81 @@ class AutoRollbackTest(PersistTest):
|
||||
users.drop(conn2)
|
||||
conn2.close()
|
||||
|
||||
class ExplicitAutoCommitTest(PersistTest):
|
||||
"""test the 'autocommit' flag on select() and text() objects.
|
||||
|
||||
Requires Postgres so that we may define a custom function which modifies the database.
|
||||
"""
|
||||
|
||||
__only_on__ = 'postgres'
|
||||
|
||||
def setUpAll(self):
|
||||
global metadata, foo
|
||||
metadata = MetaData(testing.db)
|
||||
foo = Table('foo', metadata, Column('id', Integer, primary_key=True), Column('data', String(100)))
|
||||
metadata.create_all()
|
||||
testing.db.execute("create function insert_foo(varchar) returns integer as 'insert into foo(data) values ($1);select 1;' language sql")
|
||||
|
||||
def tearDown(self):
|
||||
foo.delete().execute()
|
||||
|
||||
def tearDownAll(self):
|
||||
testing.db.execute("drop function insert_foo(varchar)")
|
||||
metadata.drop_all()
|
||||
|
||||
def test_control(self):
|
||||
# test that not using autocommit does not commit
|
||||
conn1 = testing.db.connect()
|
||||
conn2 = testing.db.connect()
|
||||
|
||||
conn1.execute(select([func.insert_foo('data1')]))
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == []
|
||||
|
||||
conn1.execute(text("select insert_foo('moredata')"))
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == []
|
||||
|
||||
trans = conn1.begin()
|
||||
trans.commit()
|
||||
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == [('data1',), ('moredata',)]
|
||||
|
||||
conn1.close()
|
||||
conn2.close()
|
||||
|
||||
def test_explicit_compiled(self):
|
||||
conn1 = testing.db.connect()
|
||||
conn2 = testing.db.connect()
|
||||
|
||||
conn1.execute(select([func.insert_foo('data1')], autocommit=True))
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == [('data1',)]
|
||||
|
||||
conn1.execute(select([func.insert_foo('data2')]).autocommit())
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == [('data1',), ('data2',)]
|
||||
|
||||
conn1.close()
|
||||
conn2.close()
|
||||
|
||||
def test_explicit_text(self):
|
||||
conn1 = testing.db.connect()
|
||||
conn2 = testing.db.connect()
|
||||
|
||||
conn1.execute(text("select insert_foo('moredata')", autocommit=True))
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == [('moredata',)]
|
||||
|
||||
conn1.close()
|
||||
conn2.close()
|
||||
|
||||
def test_implicit_text(self):
|
||||
conn1 = testing.db.connect()
|
||||
conn2 = testing.db.connect()
|
||||
|
||||
conn1.execute(text("insert into foo (data) values ('implicitdata')"))
|
||||
assert conn2.execute(select([foo.c.data])).fetchall() == [('implicitdata',)]
|
||||
|
||||
conn1.close()
|
||||
conn2.close()
|
||||
|
||||
|
||||
class TLTransactionTest(PersistTest):
|
||||
def setUpAll(self):
|
||||
global users, metadata, tlengine
|
||||
|
||||
Reference in New Issue
Block a user