summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/dialect/postgresql/test_dialect.py155
-rw-r--r--test/orm/inheritance/test_basic.py19
-rw-r--r--test/orm/test_bulk.py94
-rw-r--r--test/orm/test_cycles.py102
-rw-r--r--test/orm/test_defaults.py82
-rw-r--r--test/orm/test_unitofwork.py52
-rw-r--r--test/orm/test_unitofworkv2.py461
-rw-r--r--test/sql/test_insert.py16
8 files changed, 664 insertions, 317 deletions
diff --git a/test/dialect/postgresql/test_dialect.py b/test/dialect/postgresql/test_dialect.py
index 1fbe870ba..cc0f3b4df 100644
--- a/test/dialect/postgresql/test_dialect.py
+++ b/test/dialect/postgresql/test_dialect.py
@@ -1,5 +1,6 @@
# coding: utf-8
import datetime
+import itertools
import logging
import logging.handlers
@@ -26,10 +27,11 @@ from sqlalchemy import Table
from sqlalchemy import testing
from sqlalchemy import text
from sqlalchemy import TypeDecorator
+from sqlalchemy import util
from sqlalchemy.dialects.postgresql import base as postgresql
from sqlalchemy.dialects.postgresql import psycopg2 as psycopg2_dialect
from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_BATCH
-from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_DEFAULT
+from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_PLAIN
from sqlalchemy.dialects.postgresql.psycopg2 import EXECUTEMANY_VALUES
from sqlalchemy.engine import cursor as _cursor
from sqlalchemy.engine import engine_from_config
@@ -45,6 +47,8 @@ from sqlalchemy.testing.assertions import AssertsExecutionResults
from sqlalchemy.testing.assertions import eq_
from sqlalchemy.testing.assertions import eq_regex
from sqlalchemy.testing.assertions import ne_
+from sqlalchemy.util import u
+from sqlalchemy.util import ue
from ...engine import test_execute
if True:
@@ -160,6 +164,7 @@ class ExecuteManyMode(object):
__backend__ = True
run_create_tables = "each"
+ run_deletes = None
options = None
@@ -174,6 +179,13 @@ class ExecuteManyMode(object):
Column("z", Integer, server_default="5"),
)
+ Table(
+ u("Unitéble2"),
+ metadata,
+ Column(u("méil"), Integer, primary_key=True),
+ Column(ue("\u6e2c\u8a66"), Integer),
+ )
+
def setup(self):
super(ExecuteManyMode, self).setup()
self.engine = engines.testing_engine(options=self.options)
@@ -343,6 +355,22 @@ class ExecuteManyMode(object):
],
)
+ def test_insert_unicode_keys(self, connection):
+ table = self.tables[u("Unitéble2")]
+
+ stmt = table.insert()
+
+ connection.execute(
+ stmt,
+ [
+ {u("méil"): 1, ue("\u6e2c\u8a66"): 1},
+ {u("méil"): 2, ue("\u6e2c\u8a66"): 2},
+ {u("méil"): 3, ue("\u6e2c\u8a66"): 3},
+ ],
+ )
+
+ eq_(connection.execute(table.select()).all(), [(1, 1), (2, 2), (3, 3)])
+
def test_update_fallback(self):
from psycopg2 import extras
@@ -423,57 +451,104 @@ class ExecutemanyBatchModeTest(ExecuteManyMode, fixtures.TablesTest):
class ExecutemanyValuesInsertsTest(ExecuteManyMode, fixtures.TablesTest):
options = {"executemany_mode": "values_only"}
- def test_insert_returning_values(self):
+ def test_insert_returning_values(self, connection):
"""the psycopg2 dialect needs to assemble a fully buffered result
with the return value of execute_values().
"""
t = self.tables.data
- with self.engine.connect() as conn:
- page_size = conn.dialect.executemany_values_page_size or 100
- data = [
- {"x": "x%d" % i, "y": "y%d" % i}
- for i in range(1, page_size * 5 + 27)
- ]
- result = conn.execute(t.insert().returning(t.c.x, t.c.y), data)
-
- eq_([tup[0] for tup in result.cursor.description], ["x", "y"])
- eq_(result.keys(), ["x", "y"])
- assert t.c.x in result.keys()
- assert t.c.id not in result.keys()
- assert not result._soft_closed
- assert isinstance(
- result.cursor_strategy,
- _cursor.FullyBufferedCursorFetchStrategy,
- )
- assert not result.cursor.closed
- assert not result.closed
- eq_(result.mappings().all(), data)
+ conn = connection
+ page_size = conn.dialect.executemany_values_page_size or 100
+ data = [
+ {"x": "x%d" % i, "y": "y%d" % i}
+ for i in range(1, page_size * 5 + 27)
+ ]
+ result = conn.execute(t.insert().returning(t.c.x, t.c.y), data)
+
+ eq_([tup[0] for tup in result.cursor.description], ["x", "y"])
+ eq_(result.keys(), ["x", "y"])
+ assert t.c.x in result.keys()
+ assert t.c.id not in result.keys()
+ assert not result._soft_closed
+ assert isinstance(
+ result.cursor_strategy, _cursor.FullyBufferedCursorFetchStrategy,
+ )
+ assert not result.cursor.closed
+ assert not result.closed
+ eq_(result.mappings().all(), data)
+
+ assert result._soft_closed
+ # assert result.closed
+ assert result.cursor is None
+
+ @testing.provide_metadata
+ def test_insert_returning_preexecute_pk(self, connection):
+ counter = itertools.count(1)
+
+ t = Table(
+ "t",
+ self.metadata,
+ Column(
+ "id",
+ Integer,
+ primary_key=True,
+ default=lambda: util.next(counter),
+ ),
+ Column("data", Integer),
+ )
+ self.metadata.create_all(connection)
+
+ result = connection.execute(
+ t.insert().return_defaults(),
+ [{"data": 1}, {"data": 2}, {"data": 3}],
+ )
- assert result._soft_closed
- # assert result.closed
- assert result.cursor is None
+ eq_(result.inserted_primary_key_rows, [(1,), (2,), (3,)])
- def test_insert_returning_defaults(self):
+ def test_insert_returning_defaults(self, connection):
t = self.tables.data
- with self.engine.connect() as conn:
+ conn = connection
- result = conn.execute(t.insert(), {"x": "x0", "y": "y0"})
- first_pk = result.inserted_primary_key[0]
+ result = conn.execute(t.insert(), {"x": "x0", "y": "y0"})
+ first_pk = result.inserted_primary_key[0]
- page_size = conn.dialect.executemany_values_page_size or 100
- total_rows = page_size * 5 + 27
- data = [
- {"x": "x%d" % i, "y": "y%d" % i} for i in range(1, total_rows)
- ]
- result = conn.execute(t.insert().returning(t.c.id, t.c.z), data)
+ page_size = conn.dialect.executemany_values_page_size or 100
+ total_rows = page_size * 5 + 27
+ data = [{"x": "x%d" % i, "y": "y%d" % i} for i in range(1, total_rows)]
+ result = conn.execute(t.insert().returning(t.c.id, t.c.z), data)
- eq_(
- result.all(),
- [(pk, 5) for pk in range(1 + first_pk, total_rows + first_pk)],
- )
+ eq_(
+ result.all(),
+ [(pk, 5) for pk in range(1 + first_pk, total_rows + first_pk)],
+ )
+
+ def test_insert_return_pks_default_values(self, connection):
+ """test sending multiple, empty rows into an INSERT and getting primary
+ key values back.
+
+ This has to use a format that indicates at least one DEFAULT in
+ multiple parameter sets, i.e. "INSERT INTO table (anycol) VALUES
+ (DEFAULT) (DEFAULT) (DEFAULT) ... RETURNING col"
+
+ """
+ t = self.tables.data
+
+ conn = connection
+
+ result = conn.execute(t.insert(), {"x": "x0", "y": "y0"})
+ first_pk = result.inserted_primary_key[0]
+
+ page_size = conn.dialect.executemany_values_page_size or 100
+ total_rows = page_size * 5 + 27
+ data = [{} for i in range(1, total_rows)]
+ result = conn.execute(t.insert().returning(t.c.id), data)
+
+ eq_(
+ result.all(),
+ [(pk,) for pk in range(1 + first_pk, total_rows + first_pk)],
+ )
def test_insert_w_newlines(self):
from psycopg2 import extras
@@ -611,7 +686,7 @@ class ExecutemanyFlagOptionsTest(fixtures.TablesTest):
def test_executemany_correct_flag_options(self):
for opt, expected in [
- (None, EXECUTEMANY_DEFAULT),
+ (None, EXECUTEMANY_PLAIN),
("batch", EXECUTEMANY_BATCH),
("values_only", EXECUTEMANY_VALUES),
("values_plus_batch", EXECUTEMANY_VALUES_PLUS_BATCH),
diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py
index e38758ee2..b4a17bf3a 100644
--- a/test/orm/inheritance/test_basic.py
+++ b/test/orm/inheritance/test_basic.py
@@ -40,6 +40,7 @@ from sqlalchemy.testing import is_
from sqlalchemy.testing import mock
from sqlalchemy.testing.assertsql import AllOf
from sqlalchemy.testing.assertsql import CompiledSQL
+from sqlalchemy.testing.assertsql import Conditional
from sqlalchemy.testing.assertsql import Or
from sqlalchemy.testing.assertsql import RegexSQL
from sqlalchemy.testing.schema import Column
@@ -1829,10 +1830,20 @@ class JoinedNoFKSortingTest(fixtures.MappedTest):
self.assert_sql_execution(
testing.db,
sess.flush,
- CompiledSQL("INSERT INTO a () VALUES ()", {}),
- CompiledSQL("INSERT INTO a () VALUES ()", {}),
- CompiledSQL("INSERT INTO a () VALUES ()", {}),
- CompiledSQL("INSERT INTO a () VALUES ()", {}),
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO a (id) VALUES (DEFAULT)", [{}, {}, {}, {}]
+ ),
+ ],
+ [
+ CompiledSQL("INSERT INTO a () VALUES ()", {}),
+ CompiledSQL("INSERT INTO a () VALUES ()", {}),
+ CompiledSQL("INSERT INTO a () VALUES ()", {}),
+ CompiledSQL("INSERT INTO a () VALUES ()", {}),
+ ],
+ ),
AllOf(
CompiledSQL(
"INSERT INTO b (id) VALUES (:id)", [{"id": 1}, {"id": 3}]
diff --git a/test/orm/test_bulk.py b/test/orm/test_bulk.py
index 79de19f68..27b187342 100644
--- a/test/orm/test_bulk.py
+++ b/test/orm/test_bulk.py
@@ -9,6 +9,7 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import mock
from sqlalchemy.testing.assertsql import CompiledSQL
+from sqlalchemy.testing.assertsql import Conditional
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
from test.orm import _fixtures
@@ -91,15 +92,29 @@ class BulkInsertUpdateTest(BulkTest, _fixtures.FixtureTest):
s.bulk_save_objects(objects, return_defaults=True)
asserter.assert_(
- CompiledSQL(
- "INSERT INTO users (name) VALUES (:name)", [{"name": "u1"}]
- ),
- CompiledSQL(
- "INSERT INTO users (name) VALUES (:name)", [{"name": "u2"}]
- ),
- CompiledSQL(
- "INSERT INTO users (name) VALUES (:name)", [{"name": "u3"}]
- ),
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ [{"name": "u1"}, {"name": "u2"}, {"name": "u3"}],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ [{"name": "u1"}],
+ ),
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ [{"name": "u2"}],
+ ),
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ [{"name": "u3"}],
+ ),
+ ],
+ )
)
eq_(objects[0].__dict__["id"], 1)
@@ -612,13 +627,30 @@ class BulkInheritanceTest(BulkTest, fixtures.MappedTest):
"VALUES (:person_id, :status, :manager_name)",
[{"person_id": 1, "status": "s1", "manager_name": "mn1"}],
),
- CompiledSQL(
- "INSERT INTO people (name, type) VALUES (:name, :type)",
- [{"type": "engineer", "name": "e1"}],
- ),
- CompiledSQL(
- "INSERT INTO people (name, type) VALUES (:name, :type)",
- [{"type": "engineer", "name": "e2"}],
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO people (name, type) "
+ "VALUES (:name, :type)",
+ [
+ {"type": "engineer", "name": "e1"},
+ {"type": "engineer", "name": "e2"},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO people (name, type) "
+ "VALUES (:name, :type)",
+ [{"type": "engineer", "name": "e1"}],
+ ),
+ CompiledSQL(
+ "INSERT INTO people (name, type) "
+ "VALUES (:name, :type)",
+ [{"type": "engineer", "name": "e2"}],
+ ),
+ ],
),
CompiledSQL(
"INSERT INTO engineers (person_id, status, primary_language) "
@@ -762,14 +794,28 @@ class BulkInheritanceTest(BulkTest, fixtures.MappedTest):
)
asserter.assert_(
- CompiledSQL(
- "INSERT INTO people (name) VALUES (:name)", [{"name": "b1"}]
- ),
- CompiledSQL(
- "INSERT INTO people (name) VALUES (:name)", [{"name": "b2"}]
- ),
- CompiledSQL(
- "INSERT INTO people (name) VALUES (:name)", [{"name": "b3"}]
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO people (name) VALUES (:name)",
+ [{"name": "b1"}, {"name": "b2"}, {"name": "b3"}],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO people (name) VALUES (:name)",
+ [{"name": "b1"}],
+ ),
+ CompiledSQL(
+ "INSERT INTO people (name) VALUES (:name)",
+ [{"name": "b2"}],
+ ),
+ CompiledSQL(
+ "INSERT INTO people (name) VALUES (:name)",
+ [{"name": "b3"}],
+ ),
+ ],
),
CompiledSQL(
"INSERT INTO managers (person_id, status, manager_name) "
diff --git a/test/orm/test_cycles.py b/test/orm/test_cycles.py
index 22a26e617..5c61a6370 100644
--- a/test/orm/test_cycles.py
+++ b/test/orm/test_cycles.py
@@ -25,6 +25,7 @@ from sqlalchemy.testing import is_
from sqlalchemy.testing import mock
from sqlalchemy.testing.assertsql import AllOf
from sqlalchemy.testing.assertsql import CompiledSQL
+from sqlalchemy.testing.assertsql import Conditional
from sqlalchemy.testing.assertsql import RegexSQL
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
@@ -910,21 +911,37 @@ class OneToManyManyToOneTest(fixtures.MappedTest):
testing.db,
sess.flush,
RegexSQL("^INSERT INTO person", {"data": "some data"}),
- RegexSQL(
- "^INSERT INTO ball",
- lambda c: {"person_id": p.id, "data": "some data"},
- ),
- RegexSQL(
- "^INSERT INTO ball",
- lambda c: {"person_id": p.id, "data": "some data"},
- ),
- RegexSQL(
- "^INSERT INTO ball",
- lambda c: {"person_id": p.id, "data": "some data"},
- ),
- RegexSQL(
- "^INSERT INTO ball",
- lambda c: {"person_id": p.id, "data": "some data"},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ RegexSQL(
+ "^INSERT INTO ball",
+ lambda c: [
+ {"person_id": p.id, "data": "some data"},
+ {"person_id": p.id, "data": "some data"},
+ {"person_id": p.id, "data": "some data"},
+ {"person_id": p.id, "data": "some data"},
+ ],
+ )
+ ],
+ [
+ RegexSQL(
+ "^INSERT INTO ball",
+ lambda c: {"person_id": p.id, "data": "some data"},
+ ),
+ RegexSQL(
+ "^INSERT INTO ball",
+ lambda c: {"person_id": p.id, "data": "some data"},
+ ),
+ RegexSQL(
+ "^INSERT INTO ball",
+ lambda c: {"person_id": p.id, "data": "some data"},
+ ),
+ RegexSQL(
+ "^INSERT INTO ball",
+ lambda c: {"person_id": p.id, "data": "some data"},
+ ),
+ ],
),
CompiledSQL(
"UPDATE person SET favorite_ball_id=:favorite_ball_id "
@@ -1054,25 +1071,42 @@ class OneToManyManyToOneTest(fixtures.MappedTest):
self.assert_sql_execution(
testing.db,
sess.flush,
- CompiledSQL(
- "INSERT INTO ball (person_id, data) "
- "VALUES (:person_id, :data)",
- {"person_id": None, "data": "some data"},
- ),
- CompiledSQL(
- "INSERT INTO ball (person_id, data) "
- "VALUES (:person_id, :data)",
- {"person_id": None, "data": "some data"},
- ),
- CompiledSQL(
- "INSERT INTO ball (person_id, data) "
- "VALUES (:person_id, :data)",
- {"person_id": None, "data": "some data"},
- ),
- CompiledSQL(
- "INSERT INTO ball (person_id, data) "
- "VALUES (:person_id, :data)",
- {"person_id": None, "data": "some data"},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO ball (person_id, data) "
+ "VALUES (:person_id, :data)",
+ [
+ {"person_id": None, "data": "some data"},
+ {"person_id": None, "data": "some data"},
+ {"person_id": None, "data": "some data"},
+ {"person_id": None, "data": "some data"},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO ball (person_id, data) "
+ "VALUES (:person_id, :data)",
+ {"person_id": None, "data": "some data"},
+ ),
+ CompiledSQL(
+ "INSERT INTO ball (person_id, data) "
+ "VALUES (:person_id, :data)",
+ {"person_id": None, "data": "some data"},
+ ),
+ CompiledSQL(
+ "INSERT INTO ball (person_id, data) "
+ "VALUES (:person_id, :data)",
+ {"person_id": None, "data": "some data"},
+ ),
+ CompiledSQL(
+ "INSERT INTO ball (person_id, data) "
+ "VALUES (:person_id, :data)",
+ {"person_id": None, "data": "some data"},
+ ),
+ ],
),
CompiledSQL(
"INSERT INTO person (favorite_ball_id, data) "
diff --git a/test/orm/test_defaults.py b/test/orm/test_defaults.py
index 5cadea5ff..94397e22a 100644
--- a/test/orm/test_defaults.py
+++ b/test/orm/test_defaults.py
@@ -11,6 +11,7 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing.assertsql import assert_engine
from sqlalchemy.testing.assertsql import CompiledSQL
+from sqlalchemy.testing.assertsql import Conditional
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
@@ -229,38 +230,57 @@ class ComputedDefaultsOnUpdateTest(fixtures.MappedTest):
eq_(t1.bar, 5 + 42)
eq_(t2.bar, 10 + 42)
- if eager and testing.db.dialect.implicit_returning:
- asserter.assert_(
- CompiledSQL(
- "INSERT INTO test (id, foo) VALUES (%(id)s, %(foo)s) "
- "RETURNING test.bar",
- [{"foo": 5, "id": 1}],
- dialect="postgresql",
- ),
- CompiledSQL(
- "INSERT INTO test (id, foo) VALUES (%(id)s, %(foo)s) "
- "RETURNING test.bar",
- [{"foo": 10, "id": 2}],
- dialect="postgresql",
- ),
- )
- else:
- asserter.assert_(
- CompiledSQL(
- "INSERT INTO test (id, foo) VALUES (:id, :foo)",
- [{"foo": 5, "id": 1}, {"foo": 10, "id": 2}],
- ),
- CompiledSQL(
- "SELECT test.bar AS test_bar FROM test "
- "WHERE test.id = :param_1",
- [{"param_1": 1}],
- ),
- CompiledSQL(
- "SELECT test.bar AS test_bar FROM test "
- "WHERE test.id = :param_1",
- [{"param_1": 2}],
- ),
+ asserter.assert_(
+ Conditional(
+ eager and testing.db.dialect.implicit_returning,
+ [
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO test (id, foo) "
+ "VALUES (%(id)s, %(foo)s) "
+ "RETURNING test.bar",
+ [{"foo": 5, "id": 1}, {"foo": 10, "id": 2}],
+ dialect="postgresql",
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO test (id, foo) "
+ "VALUES (%(id)s, %(foo)s) "
+ "RETURNING test.bar",
+ [{"foo": 5, "id": 1}],
+ dialect="postgresql",
+ ),
+ CompiledSQL(
+ "INSERT INTO test (id, foo) "
+ "VALUES (%(id)s, %(foo)s) "
+ "RETURNING test.bar",
+ [{"foo": 10, "id": 2}],
+ dialect="postgresql",
+ ),
+ ],
+ )
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO test (id, foo) VALUES (:id, :foo)",
+ [{"foo": 5, "id": 1}, {"foo": 10, "id": 2}],
+ ),
+ CompiledSQL(
+ "SELECT test.bar AS test_bar FROM test "
+ "WHERE test.id = :param_1",
+ [{"param_1": 1}],
+ ),
+ CompiledSQL(
+ "SELECT test.bar AS test_bar FROM test "
+ "WHERE test.id = :param_1",
+ [{"param_1": 2}],
+ ),
+ ],
)
+ )
@testing.combinations(
(
diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py
index 3a1594a61..306fc0d2a 100644
--- a/test/orm/test_unitofwork.py
+++ b/test/orm/test_unitofwork.py
@@ -29,6 +29,7 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing.assertsql import AllOf
from sqlalchemy.testing.assertsql import CompiledSQL
+from sqlalchemy.testing.assertsql import Conditional
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
from sqlalchemy.util import OrderedDict
@@ -2789,21 +2790,42 @@ class SaveTest2(_fixtures.FixtureTest):
self.assert_sql_execution(
testing.db,
session.flush,
- CompiledSQL(
- "INSERT INTO users (name) VALUES (:name)", {"name": "u1"}
- ),
- CompiledSQL(
- "INSERT INTO users (name) VALUES (:name)", {"name": "u2"}
- ),
- CompiledSQL(
- "INSERT INTO addresses (user_id, email_address) "
- "VALUES (:user_id, :email_address)",
- {"user_id": 1, "email_address": "a1"},
- ),
- CompiledSQL(
- "INSERT INTO addresses (user_id, email_address) "
- "VALUES (:user_id, :email_address)",
- {"user_id": 2, "email_address": "a2"},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ [{"name": "u1"}, {"name": "u2"}],
+ ),
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ [
+ {"user_id": 1, "email_address": "a1"},
+ {"user_id": 2, "email_address": "a2"},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ {"name": "u1"},
+ ),
+ CompiledSQL(
+ "INSERT INTO users (name) VALUES (:name)",
+ {"name": "u2"},
+ ),
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ {"user_id": 1, "email_address": "a1"},
+ ),
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ {"user_id": 2, "email_address": "a2"},
+ ),
+ ],
),
)
diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py
index 2bd908c8f..08dd8c966 100644
--- a/test/orm/test_unitofworkv2.py
+++ b/test/orm/test_unitofworkv2.py
@@ -27,6 +27,7 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing.assertsql import AllOf
from sqlalchemy.testing.assertsql import CompiledSQL
+from sqlalchemy.testing.assertsql import Conditional
from sqlalchemy.testing.mock import Mock
from sqlalchemy.testing.mock import patch
from sqlalchemy.testing.schema import Column
@@ -82,15 +83,30 @@ class RudimentaryFlushTest(UOWTest):
CompiledSQL(
"INSERT INTO users (name) VALUES (:name)", {"name": "u1"}
),
- CompiledSQL(
- "INSERT INTO addresses (user_id, email_address) "
- "VALUES (:user_id, :email_address)",
- lambda ctx: {"email_address": "a1", "user_id": u1.id},
- ),
- CompiledSQL(
- "INSERT INTO addresses (user_id, email_address) "
- "VALUES (:user_id, :email_address)",
- lambda ctx: {"email_address": "a2", "user_id": u1.id},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ lambda ctx: [
+ {"email_address": "a1", "user_id": u1.id},
+ {"email_address": "a2", "user_id": u1.id},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ lambda ctx: {"email_address": "a1", "user_id": u1.id},
+ ),
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ lambda ctx: {"email_address": "a2", "user_id": u1.id},
+ ),
+ ],
),
)
@@ -183,15 +199,30 @@ class RudimentaryFlushTest(UOWTest):
CompiledSQL(
"INSERT INTO users (name) VALUES (:name)", {"name": "u1"}
),
- CompiledSQL(
- "INSERT INTO addresses (user_id, email_address) "
- "VALUES (:user_id, :email_address)",
- lambda ctx: {"email_address": "a1", "user_id": u1.id},
- ),
- CompiledSQL(
- "INSERT INTO addresses (user_id, email_address) "
- "VALUES (:user_id, :email_address)",
- lambda ctx: {"email_address": "a2", "user_id": u1.id},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ lambda ctx: [
+ {"email_address": "a1", "user_id": u1.id},
+ {"email_address": "a2", "user_id": u1.id},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ lambda ctx: {"email_address": "a1", "user_id": u1.id},
+ ),
+ CompiledSQL(
+ "INSERT INTO addresses (user_id, email_address) "
+ "VALUES (:user_id, :email_address)",
+ lambda ctx: {"email_address": "a2", "user_id": u1.id},
+ ),
+ ],
),
)
@@ -767,17 +798,32 @@ class SingleCycleTest(UOWTest):
"(:parent_id, :data)",
{"parent_id": None, "data": "n1"},
),
- AllOf(
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n2"},
- ),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n3"},
- ),
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: [
+ {"parent_id": n1.id, "data": "n2"},
+ {"parent_id": n1.id, "data": "n3"},
+ ],
+ ),
+ ],
+ [
+ AllOf(
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n2"},
+ ),
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n3"},
+ ),
+ ),
+ ],
),
)
@@ -864,17 +910,32 @@ class SingleCycleTest(UOWTest):
"(:parent_id, :data)",
{"parent_id": None, "data": "n1"},
),
- AllOf(
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n2"},
- ),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n3"},
- ),
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: [
+ {"parent_id": n1.id, "data": "n2"},
+ {"parent_id": n1.id, "data": "n3"},
+ ],
+ ),
+ ],
+ [
+ AllOf(
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n2"},
+ ),
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n3"},
+ ),
+ ),
+ ],
),
)
@@ -1009,35 +1070,67 @@ class SingleCycleTest(UOWTest):
"(:parent_id, :data)",
lambda ctx: {"parent_id": None, "data": "n1"},
),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n11"},
- ),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n12"},
- ),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n1.id, "data": "n13"},
- ),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n12.id, "data": "n121"},
- ),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n12.id, "data": "n122"},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: [
+ {"parent_id": n1.id, "data": "n11"},
+ {"parent_id": n1.id, "data": "n12"},
+ {"parent_id": n1.id, "data": "n13"},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n11"},
+ ),
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n12"},
+ ),
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n1.id, "data": "n13"},
+ ),
+ ],
),
- CompiledSQL(
- "INSERT INTO nodes (parent_id, data) VALUES "
- "(:parent_id, :data)",
- lambda ctx: {"parent_id": n12.id, "data": "n123"},
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: [
+ {"parent_id": n12.id, "data": "n121"},
+ {"parent_id": n12.id, "data": "n122"},
+ {"parent_id": n12.id, "data": "n123"},
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n12.id, "data": "n121"},
+ ),
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n12.id, "data": "n122"},
+ ),
+ CompiledSQL(
+ "INSERT INTO nodes (parent_id, data) VALUES "
+ "(:parent_id, :data)",
+ lambda ctx: {"parent_id": n12.id, "data": "n123"},
+ ),
+ ],
),
)
@@ -1907,8 +2000,23 @@ class BatchInsertsTest(fixtures.MappedTest, testing.AssertsExecutionResults):
self.assert_sql_execution(
testing.db,
sess.flush,
- CompiledSQL("INSERT INTO t (data) VALUES (:data)", {"data": "t1"}),
- CompiledSQL("INSERT INTO t (data) VALUES (:data)", {"data": "t2"}),
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO t (data) VALUES (:data)",
+ [{"data": "t1"}, {"data": "t2"}],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO t (data) VALUES (:data)", {"data": "t1"}
+ ),
+ CompiledSQL(
+ "INSERT INTO t (data) VALUES (:data)", {"data": "t2"}
+ ),
+ ],
+ ),
CompiledSQL(
"INSERT INTO t (id, data) VALUES (:id, :data)",
[
@@ -2256,40 +2364,56 @@ class EagerDefaultsTest(fixtures.MappedTest):
s.add_all([t1, t2])
- if testing.db.dialect.implicit_returning:
- self.assert_sql_execution(
- testing.db,
- s.commit,
- CompiledSQL(
- "INSERT INTO test (id) VALUES (%(id)s) RETURNING test.foo",
- [{"id": 1}],
- dialect="postgresql",
- ),
- CompiledSQL(
- "INSERT INTO test (id) VALUES (%(id)s) RETURNING test.foo",
- [{"id": 2}],
- dialect="postgresql",
- ),
- )
- else:
- self.assert_sql_execution(
- testing.db,
- s.commit,
- CompiledSQL(
- "INSERT INTO test (id) VALUES (:id)",
- [{"id": 1}, {"id": 2}],
- ),
- CompiledSQL(
- "SELECT test.foo AS test_foo FROM test "
- "WHERE test.id = :param_1",
- [{"param_1": 1}],
- ),
- CompiledSQL(
- "SELECT test.foo AS test_foo FROM test "
- "WHERE test.id = :param_1",
- [{"param_1": 2}],
- ),
- )
+ self.assert_sql_execution(
+ testing.db,
+ s.commit,
+ Conditional(
+ testing.db.dialect.implicit_returning,
+ [
+ Conditional(
+ testing.db.dialect.insert_executemany_returning,
+ [
+ CompiledSQL(
+ "INSERT INTO test (id) VALUES (%(id)s) "
+ "RETURNING test.foo",
+ [{"id": 1}, {"id": 2}],
+ dialect="postgresql",
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO test (id) VALUES (%(id)s) "
+ "RETURNING test.foo",
+ [{"id": 1}],
+ dialect="postgresql",
+ ),
+ CompiledSQL(
+ "INSERT INTO test (id) VALUES (%(id)s) "
+ "RETURNING test.foo",
+ [{"id": 2}],
+ dialect="postgresql",
+ ),
+ ],
+ ),
+ ],
+ [
+ CompiledSQL(
+ "INSERT INTO test (id) VALUES (:id)",
+ [{"id": 1}, {"id": 2}],
+ ),
+ CompiledSQL(
+ "SELECT test.foo AS test_foo FROM test "
+ "WHERE test.id = :param_1",
+ [{"param_1": 1}],
+ ),
+ CompiledSQL(
+ "SELECT test.foo AS test_foo FROM test "
+ "WHERE test.id = :param_1",
+ [{"param_1": 2}],
+ ),
+ ],
+ ),
+ )
def test_update_defaults_nonpresent(self):
Thing2 = self.classes.Thing2
@@ -2312,70 +2436,71 @@ class EagerDefaultsTest(fixtures.MappedTest):
t4.foo = 8
t4.bar = 12
- if testing.db.dialect.implicit_returning:
- self.assert_sql_execution(
- testing.db,
- s.flush,
- CompiledSQL(
- "UPDATE test2 SET foo=%(foo)s "
- "WHERE test2.id = %(test2_id)s "
- "RETURNING test2.bar",
- [{"foo": 5, "test2_id": 1}],
- dialect="postgresql",
- ),
- CompiledSQL(
- "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s "
- "WHERE test2.id = %(test2_id)s",
- [{"foo": 6, "bar": 10, "test2_id": 2}],
- dialect="postgresql",
- ),
- CompiledSQL(
- "UPDATE test2 SET foo=%(foo)s "
- "WHERE test2.id = %(test2_id)s "
- "RETURNING test2.bar",
- [{"foo": 7, "test2_id": 3}],
- dialect="postgresql",
- ),
- CompiledSQL(
- "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s "
- "WHERE test2.id = %(test2_id)s",
- [{"foo": 8, "bar": 12, "test2_id": 4}],
- dialect="postgresql",
- ),
- )
- else:
- self.assert_sql_execution(
- testing.db,
- s.flush,
- CompiledSQL(
- "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id",
- [{"foo": 5, "test2_id": 1}],
- ),
- CompiledSQL(
- "UPDATE test2 SET foo=:foo, bar=:bar "
- "WHERE test2.id = :test2_id",
- [{"foo": 6, "bar": 10, "test2_id": 2}],
- ),
- CompiledSQL(
- "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id",
- [{"foo": 7, "test2_id": 3}],
- ),
- CompiledSQL(
- "UPDATE test2 SET foo=:foo, bar=:bar "
- "WHERE test2.id = :test2_id",
- [{"foo": 8, "bar": 12, "test2_id": 4}],
- ),
- CompiledSQL(
- "SELECT test2.bar AS test2_bar FROM test2 "
- "WHERE test2.id = :param_1",
- [{"param_1": 1}],
- ),
- CompiledSQL(
- "SELECT test2.bar AS test2_bar FROM test2 "
- "WHERE test2.id = :param_1",
- [{"param_1": 3}],
- ),
- )
+ self.assert_sql_execution(
+ testing.db,
+ s.flush,
+ Conditional(
+ testing.db.dialect.implicit_returning,
+ [
+ CompiledSQL(
+ "UPDATE test2 SET foo=%(foo)s "
+ "WHERE test2.id = %(test2_id)s "
+ "RETURNING test2.bar",
+ [{"foo": 5, "test2_id": 1}],
+ dialect="postgresql",
+ ),
+ CompiledSQL(
+ "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s "
+ "WHERE test2.id = %(test2_id)s",
+ [{"foo": 6, "bar": 10, "test2_id": 2}],
+ dialect="postgresql",
+ ),
+ CompiledSQL(
+ "UPDATE test2 SET foo=%(foo)s "
+ "WHERE test2.id = %(test2_id)s "
+ "RETURNING test2.bar",
+ [{"foo": 7, "test2_id": 3}],
+ dialect="postgresql",
+ ),
+ CompiledSQL(
+ "UPDATE test2 SET foo=%(foo)s, bar=%(bar)s "
+ "WHERE test2.id = %(test2_id)s",
+ [{"foo": 8, "bar": 12, "test2_id": 4}],
+ dialect="postgresql",
+ ),
+ ],
+ [
+ CompiledSQL(
+ "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id",
+ [{"foo": 5, "test2_id": 1}],
+ ),
+ CompiledSQL(
+ "UPDATE test2 SET foo=:foo, bar=:bar "
+ "WHERE test2.id = :test2_id",
+ [{"foo": 6, "bar": 10, "test2_id": 2}],
+ ),
+ CompiledSQL(
+ "UPDATE test2 SET foo=:foo WHERE test2.id = :test2_id",
+ [{"foo": 7, "test2_id": 3}],
+ ),
+ CompiledSQL(
+ "UPDATE test2 SET foo=:foo, bar=:bar "
+ "WHERE test2.id = :test2_id",
+ [{"foo": 8, "bar": 12, "test2_id": 4}],
+ ),
+ CompiledSQL(
+ "SELECT test2.bar AS test2_bar FROM test2 "
+ "WHERE test2.id = :param_1",
+ [{"param_1": 1}],
+ ),
+ CompiledSQL(
+ "SELECT test2.bar AS test2_bar FROM test2 "
+ "WHERE test2.id = :param_1",
+ [{"param_1": 3}],
+ ),
+ ],
+ ),
+ )
def go():
eq_(t1.bar, 2)
diff --git a/test/sql/test_insert.py b/test/sql/test_insert.py
index c7749e74c..e5f2fbe6d 100644
--- a/test/sql/test_insert.py
+++ b/test/sql/test_insert.py
@@ -936,11 +936,25 @@ class EmptyTest(_InsertTestBase, fixtures.TablesTest, AssertsCompiledSQL):
dialect = default.DefaultDialect()
dialect.supports_empty_insert = dialect.supports_default_values = True
- stmt = table1.insert().values({}) # hide from 2to3
+ stmt = table1.insert().values({})
self.assert_compile(
stmt, "INSERT INTO mytable DEFAULT VALUES", dialect=dialect
)
+ def test_supports_empty_insert_true_executemany_mode(self):
+ table1 = self.tables.mytable
+
+ dialect = default.DefaultDialect()
+ dialect.supports_empty_insert = dialect.supports_default_values = True
+
+ stmt = table1.insert().values({})
+ self.assert_compile(
+ stmt,
+ "INSERT INTO mytable (myid) VALUES (DEFAULT)",
+ dialect=dialect,
+ for_executemany=True,
+ )
+
def test_supports_empty_insert_false(self):
table1 = self.tables.mytable