Skip to content

Commit 193e596

Browse files
authored
SNOW-629067 connector executemany handle escaping double percents when no params (#315)
1 parent d165925 commit 193e596

File tree

2 files changed

+12
-15
lines changed

2 files changed

+12
-15
lines changed

src/snowflake/sqlalchemy/base.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ def render_literal_value(self, value, type_):
400400

401401

402402
class SnowflakeExecutionContext(default.DefaultExecutionContext):
403+
INSERT_SQL_RE = re.compile(r"^insert\s+into", flags=re.IGNORECASE)
404+
403405
def fire_sequence(self, seq, type_):
404406
return self._execute_scalar(
405407
f"SELECT {self.identifier_preparer.format_sequence(seq)}.nextval",
@@ -425,7 +427,7 @@ def should_autocommit(self):
425427
return autocommit and not self.isddl
426428

427429
def pre_exec(self):
428-
if self.compiled:
430+
if self.compiled and self.identifier_preparer._double_percents:
429431
# for compiled statements, percent is doubled for escape, we turn on _interpolate_empty_sequences
430432
if hasattr(self._dbapi_connection, "driver_connection"):
431433
# _dbapi_connection is a _ConnectionFairy which proxies raw SnowflakeConnection
@@ -436,8 +438,15 @@ def pre_exec(self):
436438
# _dbapi_connection is a raw SnowflakeConnection
437439
self._dbapi_connection._interpolate_empty_sequences = True
438440

441+
# if the statement is executemany insert, setting _interpolate_empty_sequences to True is not enough,
442+
# because executemany pre-processes the param binding and then pass None params to execute so
443+
# _interpolate_empty_sequences condition not getting met for the command.
444+
# Therefore, we manually revert the escape percent in the command here
445+
if self.executemany and self.INSERT_SQL_RE.match(self.statement):
446+
self.statement = self.statement.replace("%%", "%")
447+
439448
def post_exec(self):
440-
if self.compiled:
449+
if self.compiled and self.identifier_preparer._double_percents:
441450
# for compiled statements, percent is doubled for escapeafter execution
442451
# we reset _interpolate_empty_sequences to false which is turned on in pre_exec
443452
if hasattr(self._dbapi_connection, "driver_connection"):

tests/sqlalchemy_test_suite/test_suite.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from sqlalchemy.testing.suite import InsertBehaviorTest as _InsertBehaviorTest
1212
from sqlalchemy.testing.suite import LikeFunctionsTest as _LikeFunctionsTest
1313
from sqlalchemy.testing.suite import LongNameBlowoutTest as _LongNameBlowoutTest
14-
from sqlalchemy.testing.suite import PercentSchemaNamesTest as _PercentSchemaNamesTest
1514
from sqlalchemy.testing.suite import SimpleUpdateDeleteTest as _SimpleUpdateDeleteTest
1615
from sqlalchemy.testing.suite import * # noqa
1716

@@ -68,18 +67,7 @@ def test_empty_insert_multiple(self, connection):
6867
pass
6968

7069

71-
# 3. Need fix in connector
72-
73-
74-
class PercentSchemaNamesTest(_PercentSchemaNamesTest):
75-
@pytest.mark.xfail
76-
# TODO: connector cursor "executemany" needs to handle double percentage like
77-
# "execute" using self._dbapi_connection._interpolate_empty_sequences
78-
def test_executemany_roundtrip(self, connection):
79-
super().test_executemany_roundtrip(connection)
80-
81-
82-
# 4. Patched Tests
70+
# 2. Patched Tests
8371

8472

8573
class HasSequenceTest(_HasSequenceTest):

0 commit comments

Comments
 (0)