From: Eric Atkin Date: Thu, 22 Feb 2018 19:16:14 +0000 (-0500) Subject: Quote cte alias if needed X-Git-Tag: rel_1_2_4~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b6e4a16809744255213a4598dc49a9cff9738b0b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Quote cte alias if needed Fixed bug where CTE expressions would not have their name or alias name quoted when the given name is case sensitive or otherwise requires quoting. Pull request courtesy Eric Atkin. Fixes: #4197 Change-Id: Ib8573e82b9a1ca94b50c7c5d73ee98b79465d689 Pull-request: https://github.com/zzzeek/sqlalchemy/pull/426 --- diff --git a/doc/build/changelog/unreleased_12/4197.rst b/doc/build/changelog/unreleased_12/4197.rst new file mode 100644 index 0000000000..6e24c46e9d --- /dev/null +++ b/doc/build/changelog/unreleased_12/4197.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, sql + :tickets: 4197 + + Fixed bug where CTE expressions would not have their name or alias name + quoted when the given name is case sensitive or otherwise requires quoting. + Pull request courtesy Eric Atkin. diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 560585cabd..be41e80c5b 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -1427,6 +1427,8 @@ class SQLCompiler(Compiled): if asfrom: if cte_alias_name: text = self.preparer.format_alias(cte, cte_alias_name) + if self.preparer._requires_quotes(cte_name): + cte_name = self.preparer.quote(cte_name) text += self.get_render_as_alias_suffix(cte_name) else: return self.preparer.format_alias(cte, cte_name) diff --git a/test/sql/test_cte.py b/test/sql/test_cte.py index f33516cc20..aadd470e8d 100644 --- a/test/sql/test_cte.py +++ b/test/sql/test_cte.py @@ -4,7 +4,7 @@ from sqlalchemy.sql import table, column, select, func, literal, exists, and_ from sqlalchemy.dialects import mssql from sqlalchemy.engine import default from sqlalchemy.exc import CompileError - +from sqlalchemy.sql.elements import quoted_name class CTETest(fixtures.TestBase, AssertsCompiledSQL): @@ -319,6 +319,47 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL): '(SELECT "CTE".id AS id FROM "CTE") AS anon_2' ) + def test_named_alias_no_quote(self): + cte = select([literal(1).label("id")]).cte(name='CTE') + + s1 = select([cte.c.id]).alias(name="no_quotes") + + s = select([s1]) + self.assert_compile( + s, + 'WITH "CTE" AS (SELECT :param_1 AS id) ' + 'SELECT no_quotes.id FROM ' + '(SELECT "CTE".id AS id FROM "CTE") AS no_quotes' + ) + + def test_named_alias_quote(self): + cte = select([literal(1).label("id")]).cte(name='CTE') + + s1 = select([cte.c.id]).alias(name="Quotes Required") + + s = select([s1]) + self.assert_compile( + s, + 'WITH "CTE" AS (SELECT :param_1 AS id) ' + 'SELECT "Quotes Required".id FROM ' + '(SELECT "CTE".id AS id FROM "CTE") AS "Quotes Required"' + ) + + def test_named_alias_disable_quote(self): + cte = select([literal(1).label("id")]).cte( + name=quoted_name('CTE', quote=False)) + + s1 = select([cte.c.id]).alias( + name=quoted_name("DontQuote", quote=False)) + + s = select([s1]) + self.assert_compile( + s, + 'WITH CTE AS (SELECT :param_1 AS id) ' + 'SELECT DontQuote.id FROM ' + '(SELECT CTE.id AS id FROM CTE) AS DontQuote' + ) + def test_positional_binds(self): orders = table('orders', column('order'),