diff options
Diffstat (limited to 'test/sql')
| -rw-r--r-- | test/sql/test_compare.py | 46 | ||||
| -rw-r--r-- | test/sql/test_compiler.py | 112 | ||||
| -rw-r--r-- | test/sql/test_external_traversal.py | 2 | ||||
| -rw-r--r-- | test/sql/test_functions.py | 5 | ||||
| -rw-r--r-- | test/sql/test_resultset.py | 107 | ||||
| -rw-r--r-- | test/sql/test_selectable.py | 8 |
6 files changed, 263 insertions, 17 deletions
diff --git a/test/sql/test_compare.py b/test/sql/test_compare.py index ab612053e..2800f8248 100644 --- a/test/sql/test_compare.py +++ b/test/sql/test_compare.py @@ -61,6 +61,7 @@ from sqlalchemy.sql.visitors import InternalTraversal from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_false +from sqlalchemy.testing import is_not_ from sqlalchemy.testing import is_true from sqlalchemy.testing import ne_ from sqlalchemy.testing.util import random_choices @@ -174,6 +175,14 @@ class CoreFixtures(object): table_a.c.a._annotate( {"orm": True, "parententity": MyEntity("b", select([table_a]))} ), + table_a.c.a._annotate( + { + "orm": True, + "parententity": MyEntity( + "b", select([table_a]).where(table_a.c.a == 5) + ), + } + ), ), lambda: ( table_a, @@ -759,6 +768,43 @@ class CacheKeyTest(CacheKeyFixture, CoreFixtures, fixtures.TestBase): f1._copy_internals() f2._copy_internals() + def test_generative_cache_key_regen(self): + t1 = table("t1", column("a"), column("b")) + + s1 = select([t1]) + + ck1 = s1._generate_cache_key() + + s2 = s1.where(t1.c.a == 5) + + ck2 = s2._generate_cache_key() + + ne_(ck1, ck2) + is_not_(ck1, None) + is_not_(ck2, None) + + def test_generative_cache_key_regen_w_del(self): + t1 = table("t1", column("a"), column("b")) + + s1 = select([t1]) + + ck1 = s1._generate_cache_key() + + s2 = s1.where(t1.c.a == 5) + + del s1 + + # there is now a good chance that id(s3) == id(s1), make sure + # cache key is regenerated + + s3 = s2.order_by(t1.c.b) + + ck3 = s3._generate_cache_key() + + ne_(ck1, ck3) + is_not_(ck1, None) + is_not_(ck3, None) + class CompareAndCopyTest(CoreFixtures, fixtures.TestBase): @classmethod diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 151ecb1d2..e44deed90 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -3344,6 +3344,116 @@ class BindParameterTest(AssertsCompiledSQL, fixtures.TestBase): _group_number=2, ) + @testing.combinations( + ( + select([table1]).where(table1.c.myid == 5), + select([table1]).where(table1.c.myid == 10), + {"myid_1": 5}, + {"myid_1": 10}, + None, + None, + ), + ( + select([table1]).where( + table1.c.myid + == bindparam(None, unique=True, callable_=lambda: 5) + ), + select([table1]).where( + table1.c.myid + == bindparam(None, unique=True, callable_=lambda: 10) + ), + {"param_1": 5}, + {"param_1": 10}, + None, + None, + ), + ( + table1.update() + .where(table1.c.myid == 5) + .values(name="n1", description="d1"), + table1.update() + .where(table1.c.myid == 10) + .values(name="n2", description="d2"), + {"description": "d1", "myid_1": 5, "name": "n1"}, + {"description": "d2", "myid_1": 10, "name": "n2"}, + None, + None, + ), + ( + table1.update().where(table1.c.myid == 5), + table1.update().where(table1.c.myid == 10), + {"description": "d1", "myid_1": 5, "name": "n1"}, + {"description": "d2", "myid_1": 10, "name": "n2"}, + {"description": "d1", "name": "n1"}, + {"description": "d2", "name": "n2"}, + ), + ( + table1.update().where( + table1.c.myid + == bindparam(None, unique=True, callable_=lambda: 5) + ), + table1.update().where( + table1.c.myid + == bindparam(None, unique=True, callable_=lambda: 10) + ), + {"description": "d1", "param_1": 5, "name": "n1"}, + {"description": "d2", "param_1": 10, "name": "n2"}, + {"description": "d1", "name": "n1"}, + {"description": "d2", "name": "n2"}, + ), + ( + union( + select([table1]).where(table1.c.myid == 5), + select([table1]).where(table1.c.myid == 12), + ), + union( + select([table1]).where(table1.c.myid == 5), + select([table1]).where(table1.c.myid == 15), + ), + {"myid_1": 5, "myid_2": 12}, + {"myid_1": 5, "myid_2": 15}, + None, + None, + ), + ) + def test_construct_params_combine_extracted( + self, stmt1, stmt2, param1, param2, extparam1, extparam2 + ): + + if extparam1: + keys = list(extparam1) + else: + keys = [] + + s1_cache_key = stmt1._generate_cache_key() + s1_compiled = stmt1.compile(cache_key=s1_cache_key, column_keys=keys) + + s2_cache_key = stmt2._generate_cache_key() + + eq_(s1_compiled.construct_params(params=extparam1), param1) + eq_( + s1_compiled.construct_params( + params=extparam1, extracted_parameters=s1_cache_key[1] + ), + param1, + ) + + eq_( + s1_compiled.construct_params( + params=extparam2, extracted_parameters=s2_cache_key[1] + ), + param2, + ) + + s1_compiled_no_cache_key = stmt1.compile() + assert_raises_message( + exc.CompileError, + "This compiled object has no original cache key; can't pass " + "extracted_parameters to construct_params", + s1_compiled_no_cache_key.construct_params, + extracted_parameters=s1_cache_key[1], + ) + def test_tuple_expanding_in_no_values(self): expr = tuple_(table1.c.myid, table1.c.name).in_( [(1, "foo"), (5, "bar")] @@ -5021,7 +5131,7 @@ class ResultMapTest(fixtures.TestBase): stmt = select([t.c.x, t.c.y, l1, t.c.y, l2, t.c.x, l3]) # so the statement has 7 inner columns... - eq_(len(list(stmt.inner_columns)), 7) + eq_(len(list(stmt.selected_columns)), 7) # 7 are exposed as of 1.4, no more deduping eq_(len(stmt.subquery().c), 7) diff --git a/test/sql/test_external_traversal.py b/test/sql/test_external_traversal.py index ac423931f..37fb752fe 100644 --- a/test/sql/test_external_traversal.py +++ b/test/sql/test_external_traversal.py @@ -172,7 +172,7 @@ class TraversalTest(fixtures.TestBase, AssertsExecutionResults): vis = Vis() s2 = vis.traverse(s1) - eq_(list(s2.inner_columns)[0].anon_label, c1.anon_label) + eq_(list(s2.selected_columns)[0].anon_label, c1.anon_label) def test_change_in_place(self): struct = B( diff --git a/test/sql/test_functions.py b/test/sql/test_functions.py index fd3f55780..5a6e6252b 100644 --- a/test/sql/test_functions.py +++ b/test/sql/test_functions.py @@ -468,9 +468,12 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "my_func(:my_func_1, :my_func_2, NULL, :my_func_3)", ) + f1 = func.my_func(1, 2, None, 3) + f1._generate_cache_key() + # test pickling self.assert_compile( - util.pickle.loads(util.pickle.dumps(func.my_func(1, 2, None, 3))), + util.pickle.loads(util.pickle.dumps(f1)), "my_func(:my_func_1, :my_func_2, NULL, :my_func_3)", ) diff --git a/test/sql/test_resultset.py b/test/sql/test_resultset.py index f08248440..253ad7b38 100644 --- a/test/sql/test_resultset.py +++ b/test/sql/test_resultset.py @@ -29,9 +29,11 @@ from sqlalchemy.engine import default from sqlalchemy.engine import result as _result from sqlalchemy.engine import Row from sqlalchemy.ext.compiler import compiles +from sqlalchemy.sql import ColumnElement from sqlalchemy.sql import expression from sqlalchemy.sql.selectable import TextualSelect from sqlalchemy.sql.sqltypes import NULLTYPE +from sqlalchemy.sql.util import ClauseAdapter from sqlalchemy.testing import assert_raises from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import assertions @@ -1391,16 +1393,20 @@ class KeyTargetingTest(fixtures.TablesTest): @classmethod def insert_data(cls): - cls.tables.keyed1.insert().execute(dict(b="a1", q="c1")) - cls.tables.keyed2.insert().execute(dict(a="a2", b="b2")) - cls.tables.keyed3.insert().execute(dict(a="a3", d="d3")) - cls.tables.keyed4.insert().execute(dict(b="b4", q="q4")) - cls.tables.content.insert().execute(type="t1") - - if testing.requires.schemas.enabled: - cls.tables[ - "%s.wschema" % testing.config.test_schema - ].insert().execute(dict(b="a1", q="c1")) + with testing.db.begin() as conn: + conn.execute(cls.tables.keyed1.insert(), dict(b="a1", q="c1")) + conn.execute(cls.tables.keyed2.insert(), dict(a="a2", b="b2")) + conn.execute(cls.tables.keyed3.insert(), dict(a="a3", d="d3")) + conn.execute(cls.tables.keyed4.insert(), dict(b="b4", q="q4")) + conn.execute(cls.tables.content.insert(), dict(type="t1")) + + if testing.requires.schemas.enabled: + conn.execute( + cls.tables[ + "%s.wschema" % testing.config.test_schema + ].insert(), + dict(b="a1", q="c1"), + ) @testing.requires.schemas def test_keyed_accessor_wschema(self): @@ -1712,6 +1718,87 @@ class KeyTargetingTest(fixtures.TablesTest): in_(stmt.selected_columns.keyed2_a, row._mapping) in_(stmt.selected_columns.keyed2_b, row._mapping) + def _adapt_result_columns_fixture_one(self): + keyed1 = self.tables.keyed1 + stmt = ( + select([keyed1.c.b, keyed1.c.q.label("foo")]) + .apply_labels() + .subquery() + ) + + return select([stmt.c.keyed1_b, stmt.c.foo]) + + def _adapt_result_columns_fixture_two(self): + return text("select a AS keyed2_a, b AS keyed2_b from keyed2").columns( + keyed2_a=CHAR, keyed2_b=CHAR + ) + + def _adapt_result_columns_fixture_three(self): + keyed1 = self.tables.keyed1 + stmt = select([keyed1.c.b, keyed1.c.q.label("foo")]).subquery() + + return select([stmt.c.b, stmt.c.foo]) + + def _adapt_result_columns_fixture_four(self): + keyed1 = self.tables.keyed1 + + stmt1 = select([keyed1]).apply_labels() + + a1 = keyed1.alias() + stmt2 = ClauseAdapter(a1).traverse(stmt1) + + return stmt2 + + @testing.combinations( + _adapt_result_columns_fixture_one, + _adapt_result_columns_fixture_two, + _adapt_result_columns_fixture_three, + _adapt_result_columns_fixture_four, + argnames="stmt_fn", + ) + def test_adapt_result_columns(self, connection, stmt_fn): + """test adaptation of a CursorResultMetadata to another one. + + + This copies the _keymap from one to the other in terms of the + selected columns of a target selectable. + + This is used by the statement caching process to re-use the + CursorResultMetadata from the cached statement against the same + statement sent separately. + + """ + + stmt1 = stmt_fn(self) + stmt2 = stmt_fn(self) + + eq_(stmt1._generate_cache_key(), stmt2._generate_cache_key()) + + column_linkage = dict( + zip(stmt1.selected_columns, stmt2.selected_columns) + ) + + result = connection.execute(stmt1) + + mock_context = Mock( + compiled=result.context.compiled, invoked_statement=stmt2 + ) + existing_metadata = result._metadata + adapted_metadata = existing_metadata._adapt_to_context(mock_context) + + eq_(existing_metadata.keys, adapted_metadata.keys) + + for k in existing_metadata._keymap: + if isinstance(k, ColumnElement) and k in column_linkage: + other_k = column_linkage[k] + else: + other_k = k + + is_( + existing_metadata._keymap[k], adapted_metadata._keymap[other_k] + ) + return stmt1, existing_metadata, stmt2, adapted_metadata + class PositionalTextTest(fixtures.TablesTest): run_inserts = "once" diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 58e7ee6a1..8fb1f2951 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -1973,10 +1973,10 @@ class ReduceTest(fixtures.TestBase, AssertsExecutionResults): ) s1 = select([t1, t2]) s2 = s1.reduce_columns(only_synonyms=False) - eq_(set(s2.inner_columns), set([t1.c.x, t1.c.y, t2.c.q])) + eq_(set(s2.selected_columns), set([t1.c.x, t1.c.y, t2.c.q])) s2 = s1.reduce_columns() - eq_(set(s2.inner_columns), set([t1.c.x, t1.c.y, t2.c.z, t2.c.q])) + eq_(set(s2.selected_columns), set([t1.c.x, t1.c.y, t2.c.z, t2.c.q])) def test_reduce_only_synonym_fk(self): m = MetaData() @@ -2019,7 +2019,7 @@ class ReduceTest(fixtures.TestBase, AssertsExecutionResults): s1 = select([t1]).subquery() s2 = select([t1, s1]).where(t1.c.x == s1.c.x).where(s1.c.y == t1.c.z) eq_( - set(s2.reduce_columns().inner_columns), + set(s2.reduce_columns().selected_columns), set([t1.c.x, t1.c.y, t1.c.z, s1.c.y, s1.c.z]), ) @@ -2027,7 +2027,7 @@ class ReduceTest(fixtures.TestBase, AssertsExecutionResults): s1 = select([t1]).subquery() s2 = select([s1, t1]).where(t1.c.x == s1.c.x).where(s1.c.y == t1.c.z) eq_( - set(s2.reduce_columns().inner_columns), + set(s2.reduce_columns().selected_columns), set([s1.c.x, t1.c.y, t1.c.z, s1.c.y, s1.c.z]), ) |
