Skip to content

Commit b4e0b24

Browse files
mogrify empty args under options
1 parent 374a4bc commit b4e0b24

File tree

7 files changed

+36
-8
lines changed

7 files changed

+36
-8
lines changed

singlestoredb/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@
251251
environ='SINGLESTOREDB_VECTOR_DATA_FORMAT',
252252
)
253253

254+
register_option(
255+
'mogrify_empty_args', 'bool', check_bool, False,
256+
'Should mogrify apply string interpolation when args is an empty tuple/list? ',
257+
environ='SINGLESTOREDB_MOGRIFY_EMPTY_ARGS',
258+
)
259+
254260
register_option(
255261
'fusion.enabled', 'bool', check_bool, False,
256262
'Should Fusion SQL queries be enabled?',

singlestoredb/connection.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ def _convert_params(
11201120
params: Optional[Union[Sequence[Any], Dict[str, Any], Any]],
11211121
) -> Tuple[Any, ...]:
11221122
"""Convert query to correct parameter format."""
1123-
if params is not None:
1123+
if params:
11241124

11251125
if cls._map_param_converter is None:
11261126
cls._map_param_converter = sqlparams.SQLParams(
@@ -1333,6 +1333,7 @@ def connect(
13331333
enable_extended_data_types: Optional[bool] = None,
13341334
vector_data_format: Optional[str] = None,
13351335
parse_json: Optional[bool] = None,
1336+
mogrify_empty_args: Optional[bool] = None,
13361337
) -> Connection:
13371338
"""
13381339
Return a SingleStoreDB connection.
@@ -1418,6 +1419,9 @@ def connect(
14181419
Should extended data types (BSON, vector) be enabled?
14191420
vector_data_format : str, optional
14201421
Format for vector types: json or binary
1422+
mogrify_empty_args : bool, optional
1423+
Should the connector apply parameter interpolation even when the
1424+
parameters are empty? This corresponds to pymysql/mysqlclient's handling
14211425
14221426
Examples
14231427
--------

singlestoredb/http/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ def _execute(
553553
log_query(oper, params)
554554

555555
data: Dict[str, Any] = dict(sql=oper)
556-
if params is not None:
556+
if params:
557557
data['args'] = convert_special_params(
558558
params,
559559
nan_as_null=self._connection.connection_params['nan_as_null'],

singlestoredb/mysql/connection.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ def __init__( # noqa: C901
360360
track_env=False,
361361
enable_extended_data_types=True,
362362
vector_data_format='binary',
363+
mogrify_empty_args=None,
363364
):
364365
BaseConnection.__init__(**dict(locals()))
365366

@@ -614,6 +615,7 @@ def _config(key, arg):
614615
self._auth_plugin_map = auth_plugin_map or {}
615616
self._binary_prefix = binary_prefix
616617
self.server_public_key = server_public_key
618+
self.mogrify_empty_args = mogrify_empty_args
617619

618620
if self.connection_params['nan_as_null'] or \
619621
self.connection_params['inf_as_null']:

singlestoredb/mysql/cursors.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,12 @@ def mogrify(self, query, args=None):
181181
"""
182182
conn = self._get_db()
183183

184-
if args is not None:
184+
if conn.mogrify_empty_args:
185+
should_interpolate = args is not None
186+
else:
187+
should_interpolate = bool(args)
188+
189+
if should_interpolate:
185190
query = query % self._escape_args(args, conn)
186191

187192
return query

singlestoredb/tests/test_connection.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3145,22 +3145,24 @@ def test_f16_vectors(self):
31453145
)
31463146

31473147
def test_mogrify_val_with_percent(self):
3148+
conn = s2.connect(database=type(self).dbname, mogrify_empty_args=True)
3149+
cur = conn.cursor()
31483150
val_with_percent = 'a%a'
3149-
self.cur.execute(
3151+
cur.execute(
31503152
'''SELECT REPLACE(i, "%%", "\\%%")
31513153
FROM test_val_with_percent''',
31523154
(),
31533155
)
3154-
res1 = self.cur.fetchall()
3156+
res1 = cur.fetchall()
31553157
assert res1[0][0] == 'a\\%a'
31563158

3157-
self.cur.execute(
3159+
cur.execute(
31583160
'''SELECT REPLACE(i, "%%", "\\%%")
31593161
FROM test_val_with_percent
31603162
WHERE i = %s''',
31613163
(val_with_percent,),
31623164
)
3163-
res2 = self.cur.fetchall()
3165+
res2 = cur.fetchall()
31643166
assert res2[0][0] == 'a\\%a'
31653167

31663168

singlestoredb/utils/mogrify.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def mogrify(
123123
encoders: Optional[Encoders] = None,
124124
server_status: int = 0,
125125
binary_prefix: bool = False,
126+
mogrify_empty_args: bool = False,
126127
) -> Union[str, bytes]:
127128
"""
128129
Returns the exact string sent to the database by calling the execute() method.
@@ -135,13 +136,21 @@ def mogrify(
135136
Query to mogrify.
136137
args : Sequence[Any] or Dict[str, Any] or Any, optional
137138
Parameters used with query. (optional)
139+
mogrify_empty_args : bool, optional
140+
If True, apply string interpolation even when args is an empty tuple/list.
141+
If False, only apply when args is truthy. Defaults to False.
138142
139143
Returns
140144
-------
141145
str : The query with argument binding applied.
142146
143147
"""
144-
if args:
148+
if mogrify_empty_args:
149+
should_interpolate = args is not None
150+
else:
151+
should_interpolate = bool(args)
152+
153+
if should_interpolate:
145154
query = query % _escape_args(
146155
args, charset=charset,
147156
encoders=encoders,

0 commit comments

Comments
 (0)