From 8299d6b11a1eff41d3fee3b595ad75f905613bd1 Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Tue, 3 Oct 2023 13:32:06 -0400 Subject: [PATCH 1/8] Remove quoting on schema and table name --- sqlalchemy_redshift/dialect.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index ce755ea6..8fc18972 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -857,8 +857,8 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): fkey_d = { 'name': conname, 'constrained_columns': constrained_columns, - 'referred_schema': referred_schema, - 'referred_table': referred_table, + 'referred_schema': self.unquote(referred_schema), + 'referred_table': self.unquote(referred_table), 'referred_columns': referred_columns, } fkeys.append(fkey_d) @@ -908,6 +908,16 @@ def get_indexes(self, connection, table_name, schema, **kw): """ return [] + @staticmethod + def unquote(text): + if text is None: + return None + + if text.startswith('"') and text.endswith('"'): + return text[1:-1] + + return text + @reflection.cache def get_unique_constraints(self, connection, table_name, schema=None, **kw): @@ -1110,6 +1120,7 @@ def _get_all_relation_info(self, connection, **kw): @reflection.cache def _get_schema_column_info(self, connection, **kw): schema = kw.get('schema', None) + schema = self.unquote(schema) schema_clause = ( "AND schema = '{schema}'".format(schema=schema) if schema else "" ) From 9ec6a5e7b45ddaa155b92da936c9d15e63fbaf8a Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Tue, 3 Oct 2023 14:40:28 -0400 Subject: [PATCH 2/8] Remove quoting on schema and table name --- sqlalchemy_redshift/dialect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index 8fc18972..5c766af7 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -987,7 +987,7 @@ def _get_table_or_view_names(self, relkind, connection, schema=None, **kw): relation_names = [] for key, relation in all_relations.items(): if key.schema == schema and relation.relkind == relkind: - relation_names.append(key.name) + relation_names.append(self.unquote(key.name)) return relation_names def _get_column_info(self, *args, **kwargs): From b30a7877ee2be05063b048ceadda1f38d3b0f74c Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Wed, 4 Oct 2023 12:10:18 -0400 Subject: [PATCH 3/8] Remove quoting on schema and table name --- sqlalchemy_redshift/dialect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index 5c766af7..47d448f2 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -793,12 +793,12 @@ def get_check_constraints(self, connection, table_name, schema=None, **kw): def get_table_oid(self, connection, table_name, schema=None, **kw): """Fetch the oid for schema.table_name. Return null if not found (external table does not have table oid)""" - schema_field = '"{schema}".'.format(schema=schema) if schema else "" + schema_field = '{schema}.'.format(schema=schema) if schema else "" result = connection.execute( sa.text( """ - select '{schema_field}"{table_name}"'::regclass::oid; + select '{schema_field}{table_name}'::regclass::oid; """.format( schema_field=schema_field, table_name=table_name From 51cbeb7189d33c3bec0d3fbc37a334907c43f1c5 Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Wed, 4 Oct 2023 14:36:33 -0400 Subject: [PATCH 4/8] Remove quoting on schema and table name --- sqlalchemy_redshift/dialect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index 47d448f2..82c884a7 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -438,9 +438,9 @@ def __new__(cls, name, schema=None, connection=None): def __str__(self): if self.schema is None: - return self.name + return RelationKey._unquote(self.name) else: - return self.schema + "." + self.name + return RelationKey._unquote(self.schema) + "." + RelationKey._unquote(self.name) @staticmethod def _unquote(part): From 193fb92457a4353cd2731d7c047bcd49ea00b401 Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Fri, 6 Oct 2023 10:44:26 -0400 Subject: [PATCH 5/8] Unquoting the schema and table --- tests/rs_sqla_test_utils/models.py | 12 ++++++++++++ tests/test_compiler.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/rs_sqla_test_utils/models.py b/tests/rs_sqla_test_utils/models.py index c594fa0a..97ae9f93 100644 --- a/tests/rs_sqla_test_utils/models.py +++ b/tests/rs_sqla_test_utils/models.py @@ -32,6 +32,18 @@ class BasicInOtherSchema(Base): col1 = sa.Column(sa.Integer(), primary_key=True) +class BasicInIncludingDotSchema(Base): + __tablename__ = 'basic' + __table_args__ = ( + {'schema': 'dotted.schema', + 'quote_schema': False, + 'redshift_diststyle': 'KEY', + 'redshift_distkey': 'col1', + 'redshift_sortkey': 'col1'} + ) + col1 = sa.Column(sa.Integer(), primary_key=True) + + class ReflectionDistKey(Base): __tablename__ = 'reflection_distkey' col1 = sa.Column(sa.Integer(), primary_key=True) diff --git a/tests/test_compiler.py b/tests/test_compiler.py index 9f02f005..c913dcdd 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -1,4 +1,6 @@ -from sqlalchemy import func, select +from sqlalchemy import func, select, Table + +from tests.rs_sqla_test_utils import models def test_func_now(stub_redshift_dialect): @@ -6,3 +8,12 @@ def test_func_now(stub_redshift_dialect): s = select([func.NOW().label("time")]) compiled = s.compile(dialect=dialect) assert str(compiled) == "SELECT SYSDATE AS time" + +def test_unquoting_schema(stub_redshift_dialect): + dialect = stub_redshift_dialect + s = select(models.BasicInIncludingDotSchema.col1).where(models.BasicInIncludingDotSchema.col1 == 1) + compiled = s.compile(dialect=dialect) + assert str(compiled) == """SELECT dotted.schema.basic.col1 + FROM dotted.schema.basic + WHERE dotted.schema.basic.col1 = %s + """ From 7204c12aa8e078c3234237fb4a1d3666602f3700 Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Thu, 26 Oct 2023 14:36:58 -0400 Subject: [PATCH 6/8] TUP-0000 Set initial_quote and final_quote --- sqlalchemy_redshift/dialect.py | 4 ++++ tests/rs_sqla_test_utils/models.py | 1 - tests/test_compiler.py | 9 ++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index 82c884a7..f8095fb8 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -653,6 +653,8 @@ def visit_HLLSKETCH(self, type_, **kw): class RedshiftIdentifierPreparer(PGIdentifierPreparer): reserved_words = RESERVED_WORDS + initial_quote: str = '' + final_quote: str = '' class RedshiftDialectMixin(DefaultDialect): @@ -670,6 +672,8 @@ class RedshiftDialectMixin(DefaultDialect): statement_compiler = RedshiftCompiler ddl_compiler = RedshiftDDLCompiler preparer = RedshiftIdentifierPreparer + preparer.initial_quote = '' + preparer.final_quote = '' type_compiler = RedshiftTypeCompiler construct_arguments = [ (sa.schema.Index, { diff --git a/tests/rs_sqla_test_utils/models.py b/tests/rs_sqla_test_utils/models.py index 97ae9f93..9facd5a4 100644 --- a/tests/rs_sqla_test_utils/models.py +++ b/tests/rs_sqla_test_utils/models.py @@ -36,7 +36,6 @@ class BasicInIncludingDotSchema(Base): __tablename__ = 'basic' __table_args__ = ( {'schema': 'dotted.schema', - 'quote_schema': False, 'redshift_diststyle': 'KEY', 'redshift_distkey': 'col1', 'redshift_sortkey': 'col1'} diff --git a/tests/test_compiler.py b/tests/test_compiler.py index c913dcdd..319ac87f 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -1,4 +1,4 @@ -from sqlalchemy import func, select, Table +from sqlalchemy import func, select from tests.rs_sqla_test_utils import models @@ -13,7 +13,6 @@ def test_unquoting_schema(stub_redshift_dialect): dialect = stub_redshift_dialect s = select(models.BasicInIncludingDotSchema.col1).where(models.BasicInIncludingDotSchema.col1 == 1) compiled = s.compile(dialect=dialect) - assert str(compiled) == """SELECT dotted.schema.basic.col1 - FROM dotted.schema.basic - WHERE dotted.schema.basic.col1 = %s - """ + assert str(compiled) == """SELECT dotted.schema.basic.col1 +FROM dotted.schema.basic +WHERE dotted.schema.basic.col1 = %s""" From 22e5a2cbdfd972ac773432643e7f995e697c9843 Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Thu, 26 Oct 2023 14:40:22 -0400 Subject: [PATCH 7/8] TUP-0000 Set initial_quote and final_quote --- sqlalchemy_redshift/dialect.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index f8095fb8..d9d6b100 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -672,8 +672,6 @@ class RedshiftDialectMixin(DefaultDialect): statement_compiler = RedshiftCompiler ddl_compiler = RedshiftDDLCompiler preparer = RedshiftIdentifierPreparer - preparer.initial_quote = '' - preparer.final_quote = '' type_compiler = RedshiftTypeCompiler construct_arguments = [ (sa.schema.Index, { From 017157e108d11fa15e7e6ae7c85383f279a4929d Mon Sep 17 00:00:00 2001 From: Tin Nguyen Date: Thu, 26 Oct 2023 15:11:41 -0400 Subject: [PATCH 8/8] TUP-0000 Change approach to disable quote_schema on dialect --- sqlalchemy_redshift/dialect.py | 7 +++++-- tests/test_compiler.py | 5 ++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sqlalchemy_redshift/dialect.py b/sqlalchemy_redshift/dialect.py index d9d6b100..a61d2cb8 100644 --- a/sqlalchemy_redshift/dialect.py +++ b/sqlalchemy_redshift/dialect.py @@ -3,6 +3,7 @@ import re from collections import defaultdict, namedtuple from logging import getLogger +from typing import Any, Optional import pkg_resources import sqlalchemy as sa @@ -653,8 +654,9 @@ def visit_HLLSKETCH(self, type_, **kw): class RedshiftIdentifierPreparer(PGIdentifierPreparer): reserved_words = RESERVED_WORDS - initial_quote: str = '' - final_quote: str = '' + + def quote_schema(self, schema: Any, force: Optional[bool] = ...) -> str: + return schema class RedshiftDialectMixin(DefaultDialect): @@ -672,6 +674,7 @@ class RedshiftDialectMixin(DefaultDialect): statement_compiler = RedshiftCompiler ddl_compiler = RedshiftDDLCompiler preparer = RedshiftIdentifierPreparer + identifier_preparer = RedshiftIdentifierPreparer type_compiler = RedshiftTypeCompiler construct_arguments = [ (sa.schema.Index, { diff --git a/tests/test_compiler.py b/tests/test_compiler.py index 319ac87f..19fe7677 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -13,6 +13,5 @@ def test_unquoting_schema(stub_redshift_dialect): dialect = stub_redshift_dialect s = select(models.BasicInIncludingDotSchema.col1).where(models.BasicInIncludingDotSchema.col1 == 1) compiled = s.compile(dialect=dialect) - assert str(compiled) == """SELECT dotted.schema.basic.col1 -FROM dotted.schema.basic -WHERE dotted.schema.basic.col1 = %s""" + assert "dotted.schema" in str(compiled) + assert "\"dotted.schema\"" not in str(compiled)