from sqlalchemy import exc as exceptions, select, MetaData, Integer, or_, \ bindparam from sqlalchemy.engine import default from sqlalchemy.sql import table, column from sqlalchemy.sql.elements import _truncated_label from sqlalchemy.testing import AssertsCompiledSQL, assert_raises, engines,\ fixtures, eq_ from sqlalchemy.testing.schema import Table, Column IDENT_LENGTH = 29 class MaxIdentTest(fixtures.TestBase, AssertsCompiledSQL): __dialect__ = 'DefaultDialect' table1 = table('some_large_named_table', column('this_is_the_primarykey_column'), column('this_is_the_data_column') ) table2 = table('table_with_exactly_29_characs', column('this_is_the_primarykey_column'), column('this_is_the_data_column') ) def _length_fixture(self, length=IDENT_LENGTH, positional=False): dialect = default.DefaultDialect() dialect.max_identifier_length = length if positional: dialect.paramstyle = 'format' dialect.positional = True return dialect def _engine_fixture(self, length=IDENT_LENGTH): eng = engines.testing_engine() eng.dialect.max_identifier_length = length return eng def test_table_alias_1(self): self.assert_compile( self.table2.alias().select(), 'SELECT ' 'table_with_exactly_29_c_1.' 'this_is_the_primarykey_column, ' 'table_with_exactly_29_c_1.this_is_the_data_column ' 'FROM ' 'table_with_exactly_29_characs ' 'AS table_with_exactly_29_c_1', dialect=self._length_fixture() ) def test_table_alias_2(self): table1 = self.table1 table2 = self.table2 ta = table2.alias() on = table1.c.this_is_the_data_column == ta.c.this_is_the_data_column self.assert_compile( select([table1, ta]).select_from(table1.join(ta, on)). where(ta.c.this_is_the_data_column == 'data3'), 'SELECT ' 'some_large_named_table.this_is_the_primarykey_column, ' 'some_large_named_table.this_is_the_data_column, ' 'table_with_exactly_29_c_1.this_is_the_primarykey_column, ' 'table_with_exactly_29_c_1.this_is_the_data_column ' 'FROM ' 'some_large_named_table ' 'JOIN ' 'table_with_exactly_29_characs ' 'AS ' 'table_with_exactly_29_c_1 ' 'ON ' 'some_large_named_table.this_is_the_data_column = ' 'table_with_exactly_29_c_1.this_is_the_data_column ' 'WHERE ' 'table_with_exactly_29_c_1.this_is_the_data_column = ' ':this_is_the_data_column_1', dialect=self._length_fixture() ) def test_too_long_name_disallowed(self): m = MetaData() t = Table('this_name_is_too_long_for_what_were_doing_in_this_test', m, Column('foo', Integer)) eng = self._engine_fixture() methods = (t.create, t.drop, m.create_all, m.drop_all) for meth in methods: assert_raises(exceptions.IdentifierError, meth, eng) def _assert_labeled_table1_select(self, s): table1 = self.table1 compiled = s.compile(dialect=self._length_fixture()) assert set( compiled._create_result_map()['some_large_named_table__2'][1]).\ issuperset( [ 'some_large_named_table_this_is_the_data_column', 'some_large_named_table__2', table1.c.this_is_the_data_column ] ) assert set( compiled._create_result_map()['some_large_named_table__1'][1]).\ issuperset( [ 'some_large_named_table_this_is_the_primarykey_column', 'some_large_named_table__1', table1.c.this_is_the_primarykey_column ] ) def test_result_map_use_labels(self): table1 = self.table1 s = table1.select().apply_labels().\ order_by(table1.c.this_is_the_primarykey_column) self._assert_labeled_table1_select(s) def test_result_map_limit(self): table1 = self.table1 # some dialects such as oracle (and possibly ms-sql in a future # version) generate a subquery for limits/offsets. ensure that the # generated result map corresponds to the selected table, not the # select query s = table1.select(use_labels=True, order_by=[table1.c.this_is_the_primarykey_column]).\ limit(2) self._assert_labeled_table1_select(s) def test_result_map_subquery(self): table1 = self.table1 s = table1.select( table1.c.this_is_the_primarykey_column == 4).\ alias('foo') s2 = select([s]) compiled = s2.compile(dialect=self._length_fixture()) assert \ set(compiled._create_result_map()['this_is_the_data_column'][1]).\ issuperset(['this_is_the_data_column', s.c.this_is_the_data_column]) assert set( compiled._create_result_map()['this_is_the_primarykey__1'][1]).\ issuperset(['this_is_the_primarykey_column', 'this_is_the_primarykey__1', s.c.this_is_the_primarykey_column]) def test_result_map_anon_alias(self): table1 = self.table1 dialect = self._length_fixture() q = table1.select(table1.c.this_is_the_primarykey_column == 4).alias() s = select([q]).apply_labels() self.assert_compile( s, "SELECT " "anon_1.this_is_the_primarykey__2 AS anon_1_this_is_the_prim_1, " "anon_1.this_is_the_data_column AS anon_1_this_is_the_data_3 " "FROM (" "SELECT " "some_large_named_table." "this_is_the_primarykey_column AS this_is_the_primarykey__2, " "some_large_named_table." "this_is_the_data_column AS this_is_the_data_column " "FROM " "some_large_named_table " "WHERE " "some_large_named_table.this_is_the_primarykey_column " "= :this_is_the_primarykey__1" ") " "AS anon_1", dialect=dialect) compiled = s.compile(dialect=dialect) assert set( compiled._create_result_map()['anon_1_this_is_the_data_3'][1]).\ issuperset([ 'anon_1_this_is_the_data_3', q.corresponding_column( table1.c.this_is_the_data_column) ]) assert set( compiled._create_result_map()['anon_1_this_is_the_prim_1'][1]).\ issuperset([ 'anon_1_this_is_the_prim_1', q.corresponding_column( table1.c.this_is_the_primarykey_column) ]) def test_column_bind_labels_1(self): table1 = self.table1 s = table1.select(table1.c.this_is_the_primarykey_column == 4) self.assert_compile( s, "SELECT some_large_named_table.this_is_the_primarykey_column, " "some_large_named_table.this_is_the_data_column " "FROM some_large_named_table WHERE " "some_large_named_table.this_is_the_primarykey_column = " ":this_is_the_primarykey__1", checkparams={'this_is_the_primarykey__1': 4}, dialect=self._length_fixture() ) self.assert_compile( s, "SELECT some_large_named_table.this_is_the_primarykey_column, " "some_large_named_table.this_is_the_data_column " "FROM some_large_named_table WHERE " "some_large_named_table.this_is_the_primarykey_column = " "%s", checkpositional=(4, ), checkparams={'this_is_the_primarykey__1': 4}, dialect=self._length_fixture(positional=True) ) def test_column_bind_labels_2(self): table1 = self.table1 s = table1.select(or_( table1.c.this_is_the_primarykey_column == 4, table1.c.this_is_the_primarykey_column == 2 )) self.assert_compile( s, "SELECT some_large_named_table.this_is_the_primarykey_column, " "some_large_named_table.this_is_the_data_column " "FROM some_large_named_table WHERE " "some_large_named_table.this_is_the_primarykey_column = " ":this_is_the_primarykey__1 OR " "some_large_named_table.this_is_the_primarykey_column = " ":this_is_the_primarykey__2", checkparams={ 'this_is_the_primarykey__1': 4, 'this_is_the_primarykey__2': 2 }, dialect=self._length_fixture() ) self.assert_compile( s, "SELECT some_large_named_table.this_is_the_primarykey_column, " "some_large_named_table.this_is_the_data_column " "FROM some_large_named_table WHERE " "some_large_named_table.this_is_the_primarykey_column = " "%s OR " "some_large_named_table.this_is_the_primarykey_column = " "%s", checkparams={ 'this_is_the_primarykey__1': 4, 'this_is_the_primarykey__2': 2 }, checkpositional=(4, 2), dialect=self._length_fixture(positional=True) ) def test_bind_param_non_truncated(self): table1 = self.table1 stmt = table1.insert().values( this_is_the_data_column=bindparam( "this_is_the_long_bindparam_name") ) compiled = stmt.compile(dialect=self._length_fixture(length=10)) eq_( compiled.construct_params( params={"this_is_the_long_bindparam_name": 5}), {'this_is_the_long_bindparam_name': 5} ) def test_bind_param_truncated_named(self): table1 = self.table1 bp = bindparam(_truncated_label("this_is_the_long_bindparam_name")) stmt = table1.insert().values( this_is_the_data_column=bp ) compiled = stmt.compile(dialect=self._length_fixture(length=10)) eq_( compiled.construct_params(params={ "this_is_the_long_bindparam_name": 5}), {"this_1": 5} ) def test_bind_param_truncated_positional(self): table1 = self.table1 bp = bindparam(_truncated_label("this_is_the_long_bindparam_name")) stmt = table1.insert().values( this_is_the_data_column=bp ) compiled = stmt.compile( dialect=self._length_fixture(length=10, positional=True)) eq_( compiled.construct_params(params={ "this_is_the_long_bindparam_name": 5}), {"this_1": 5} ) class LabelLengthTest(fixtures.TestBase, AssertsCompiledSQL): __dialect__ = 'DefaultDialect' table1 = table('some_large_named_table', column('this_is_the_primarykey_column'), column('this_is_the_data_column') ) table2 = table('table_with_exactly_29_characs', column('this_is_the_primarykey_column'), column('this_is_the_data_column') ) def test_adjustable_1(self): table1 = self.table1 q = table1.select( table1.c.this_is_the_primarykey_column == 4).alias('foo') x = select([q]) compile_dialect = default.DefaultDialect(label_length=10) self.assert_compile( x, 'SELECT ' 'foo.this_1, foo.this_2 ' 'FROM (' 'SELECT ' 'some_large_named_table.this_is_the_primarykey_column ' 'AS this_1, ' 'some_large_named_table.this_is_the_data_column ' 'AS this_2 ' 'FROM ' 'some_large_named_table ' 'WHERE ' 'some_large_named_table.this_is_the_primarykey_column ' '= :this_1' ') ' 'AS foo', dialect=compile_dialect) def test_adjustable_2(self): table1 = self.table1 q = table1.select( table1.c.this_is_the_primarykey_column == 4).alias('foo') x = select([q]) compile_dialect = default.DefaultDialect(label_length=10) self.assert_compile( x, 'SELECT ' 'foo.this_1, foo.this_2 ' 'FROM (' 'SELECT ' 'some_large_named_table.this_is_the_primarykey_column ' 'AS this_1, ' 'some_large_named_table.this_is_the_data_column ' 'AS this_2 ' 'FROM ' 'some_large_named_table ' 'WHERE ' 'some_large_named_table.this_is_the_primarykey_column ' '= :this_1' ') ' 'AS foo', dialect=compile_dialect) def test_adjustable_3(self): table1 = self.table1 compile_dialect = default.DefaultDialect(label_length=4) q = table1.select( table1.c.this_is_the_primarykey_column == 4).alias('foo') x = select([q]) self.assert_compile( x, 'SELECT ' 'foo._1, foo._2 ' 'FROM (' 'SELECT ' 'some_large_named_table.this_is_the_primarykey_column ' 'AS _1, ' 'some_large_named_table.this_is_the_data_column ' 'AS _2 ' 'FROM ' 'some_large_named_table ' 'WHERE ' 'some_large_named_table.this_is_the_primarykey_column ' '= :_1' ') ' 'AS foo', dialect=compile_dialect) def test_adjustable_4(self): table1 = self.table1 q = table1.select(table1.c.this_is_the_primarykey_column == 4).alias() x = select([q], use_labels=True) compile_dialect = default.DefaultDialect(label_length=10) self.assert_compile( x, 'SELECT ' 'anon_1.this_2 AS anon_1, ' 'anon_1.this_4 AS anon_3 ' 'FROM (' 'SELECT ' 'some_large_named_table.this_is_the_primarykey_column ' 'AS this_2, ' 'some_large_named_table.this_is_the_data_column ' 'AS this_4 ' 'FROM ' 'some_large_named_table ' 'WHERE ' 'some_large_named_table.this_is_the_primarykey_column ' '= :this_1' ') ' 'AS anon_1', dialect=compile_dialect) def test_adjustable_5(self): table1 = self.table1 q = table1.select(table1.c.this_is_the_primarykey_column == 4).alias() x = select([q], use_labels=True) compile_dialect = default.DefaultDialect(label_length=4) self.assert_compile( x, 'SELECT ' '_1._2 AS _1, ' '_1._4 AS _3 ' 'FROM (' 'SELECT ' 'some_large_named_table.this_is_the_primarykey_column ' 'AS _2, ' 'some_large_named_table.this_is_the_data_column ' 'AS _4 ' 'FROM ' 'some_large_named_table ' 'WHERE ' 'some_large_named_table.this_is_the_primarykey_column ' '= :_1' ') ' 'AS _1', dialect=compile_dialect) def test_adjustable_result_schema_column_1(self): table1 = self.table1 q = table1.select( table1.c.this_is_the_primarykey_column == 4).apply_labels().\ alias('foo') dialect = default.DefaultDialect(label_length=10) compiled = q.compile(dialect=dialect) assert set(compiled._create_result_map()['some_2'][1]).issuperset([ table1.c.this_is_the_data_column, 'some_large_named_table_this_is_the_data_column', 'some_2' ]) assert set(compiled._create_result_map()['some_1'][1]).issuperset([ table1.c.this_is_the_primarykey_column, 'some_large_named_table_this_is_the_primarykey_column', 'some_1' ]) def test_adjustable_result_schema_column_2(self): table1 = self.table1 q = table1.select( table1.c.this_is_the_primarykey_column == 4).alias('foo') x = select([q]) dialect = default.DefaultDialect(label_length=10) compiled = x.compile(dialect=dialect) assert set(compiled._create_result_map()['this_2'][1]).issuperset([ q.corresponding_column(table1.c.this_is_the_data_column), 'this_is_the_data_column', 'this_2']) assert set(compiled._create_result_map()['this_1'][1]).issuperset([ q.corresponding_column(table1.c.this_is_the_primarykey_column), 'this_is_the_primarykey_column', 'this_1']) def test_table_plus_column_exceeds_length(self): """test that the truncation only occurs when tablename + colname are concatenated, if they are individually under the label length. """ compile_dialect = default.DefaultDialect(label_length=30) a_table = table( 'thirty_characters_table_xxxxxx', column('id') ) other_table = table( 'other_thirty_characters_table_', column('id'), column('thirty_characters_table_id') ) anon = a_table.alias() j1 = other_table.outerjoin( anon, anon.c.id == other_table.c.thirty_characters_table_id) self.assert_compile( select([other_table, anon]). select_from(j1).apply_labels(), 'SELECT ' 'other_thirty_characters_table_.id ' 'AS other_thirty_characters__1, ' 'other_thirty_characters_table_.thirty_characters_table_id ' 'AS other_thirty_characters__2, ' 'thirty_characters_table__1.id ' 'AS thirty_characters_table__3 ' 'FROM ' 'other_thirty_characters_table_ ' 'LEFT OUTER JOIN ' 'thirty_characters_table_xxxxxx AS thirty_characters_table__1 ' 'ON thirty_characters_table__1.id = ' 'other_thirty_characters_table_.thirty_characters_table_id', dialect=compile_dialect) def test_colnames_longer_than_labels_lowercase(self): t1 = table('a', column('abcde')) self._test_colnames_longer_than_labels(t1) def test_colnames_longer_than_labels_uppercase(self): m = MetaData() t1 = Table('a', m, Column('abcde', Integer)) self._test_colnames_longer_than_labels(t1) def _test_colnames_longer_than_labels(self, t1): dialect = default.DefaultDialect(label_length=4) a1 = t1.alias(name='asdf') # 'abcde' is longer than 4, but rendered as itself # needs to have all characters s = select([a1]) self.assert_compile(select([a1]), 'SELECT asdf.abcde FROM a AS asdf', dialect=dialect) compiled = s.compile(dialect=dialect) assert set(compiled._create_result_map()['abcde'][1]).issuperset([ 'abcde', a1.c.abcde, 'abcde']) # column still there, but short label s = select([a1]).apply_labels() self.assert_compile(s, 'SELECT asdf.abcde AS _1 FROM a AS asdf', dialect=dialect) compiled = s.compile(dialect=dialect) assert set(compiled._create_result_map()['_1'][1]).issuperset([ 'asdf_abcde', a1.c.abcde, '_1']) def test_label_overlap_unlabeled(self): """test that an anon col can't overlap with a fixed name, #3396""" table1 = table( "tablename", column('columnname_one'), column('columnn_1')) stmt = select([table1]).apply_labels() dialect = default.DefaultDialect(label_length=23) self.assert_compile( stmt, "SELECT tablename.columnname_one AS tablename_columnn_1, " "tablename.columnn_1 AS tablename_columnn_2 FROM tablename", dialect=dialect ) compiled = stmt.compile(dialect=dialect) eq_( set(compiled._create_result_map()), set(['tablename_columnn_1', 'tablename_columnn_2']) )