Skip to content

Commit aa4c445

Browse files
committed
fix(sqlalchemy-spanner): fail fast on non-string names and fix AND spacing
1 parent 0411049 commit aa4c445

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

‎packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ def _escape_sql_string_literal(value):
8686
otherwise close the literal so the remainder is parsed as SQL. Escaping the
8787
backslash, both quote characters and newlines keeps the name contained.
8888
"""
89+
if not isinstance(value, str):
90+
raise spanner_dbapi.exceptions.ProgrammingError(
91+
"Unsupported type for SQL string literal escaping: "
92+
"{!r}".format(type(value).__name__)
93+
)
8994
return (
9095
value.replace("\\", "\\\\")
9196
.replace("'", "\\'")
@@ -1549,7 +1554,7 @@ def get_multi_foreign_keys(
15491554
The schema is ``None`` if no schema is provided.
15501555
"""
15511556
table_filter_query = self._get_table_filter_query(filter_names, "tc", True)
1552-
schema_filter_query = " tc.table_schema = '{schema}' AND".format(
1557+
schema_filter_query = " tc.table_schema = '{schema}' AND ".format(
15531558
schema=_escape_sql_string_literal(schema or "")
15541559
)
15551560
table_type_query = self._get_table_type_query(kind, True)

‎packages/sqlalchemy-spanner/tests/unit/test_dialect.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
from unittest.mock import MagicMock
16+
import pytest
1617
from sqlalchemy.testing import eq_
1718
from sqlalchemy.testing.plugin.plugin_base import fixtures
1819
from google.cloud.sqlalchemy_spanner.sqlalchemy_spanner import SpannerDialect
@@ -154,3 +155,16 @@ def test_escape_sql_string_literal(self):
154155
eq_(_escape_sql_string_literal("a\\b"), "a\\\\b")
155156
eq_(_escape_sql_string_literal("a\nb"), "a\\nb")
156157
eq_(_escape_sql_string_literal("plain"), "plain")
158+
159+
def test_escape_sql_string_literal_rejects_non_string(self):
160+
"""A non-string name must fail fast rather than be silently coerced."""
161+
from google.cloud.sqlalchemy_spanner.sqlalchemy_spanner import (
162+
_escape_sql_string_literal,
163+
)
164+
from google.cloud.spanner_dbapi.exceptions import ProgrammingError
165+
166+
with pytest.raises(ProgrammingError):
167+
_escape_sql_string_literal(None)
168+
169+
with pytest.raises(ProgrammingError):
170+
_escape_sql_string_literal(123)

0 commit comments

Comments
 (0)