2020from redshift_connector .config import (
2121 DEFAULT_PROTOCOL_VERSION ,
2222 ClientProtocolVersion ,
23+ DbApiParamstyle ,
2324 _client_encoding ,
2425 max_int2 ,
2526 max_int4 ,
@@ -145,6 +146,7 @@ def convert_paramstyle(style: str, query) -> typing.Tuple[str, typing.Any]:
145146 INSIDE_ES : int = 3 # inside escaped single-quote string, E'...'
146147 INSIDE_PN : int = 4 # inside parameter name eg. :name
147148 INSIDE_CO : int = 5 # inside inline comment eg. --
149+ INSIDE_MC : int = 6 # inside multiline comment eg. /*
148150
149151 in_quote_escape : bool = False
150152 in_param_escape : bool = False
@@ -173,23 +175,27 @@ def convert_paramstyle(style: str, query) -> typing.Tuple[str, typing.Any]:
173175 output_query .append (c )
174176 if prev_c == "-" :
175177 state = INSIDE_CO
176- elif style == "qmark" and c == "?" :
178+ elif c == "*" :
179+ output_query .append (c )
180+ if prev_c == "/" :
181+ state = INSIDE_MC
182+ elif style == DbApiParamstyle .QMARK .value and c == "?" :
177183 output_query .append (next (param_idx ))
178- elif style == "numeric" and c == ":" and next_c not in ":=" and prev_c != ":" :
184+ elif style == DbApiParamstyle . NUMERIC . value and c == ":" and next_c not in ":=" and prev_c != ":" :
179185 # Treat : as beginning of parameter name if and only
180186 # if it's the only : around
181187 # Needed to properly process type conversions
182188 # i.e. sum(x)::float
183189 output_query .append ("$" )
184- elif style == "named" and c == ":" and next_c not in ":=" and prev_c != ":" :
190+ elif style == DbApiParamstyle . NAMED . value and c == ":" and next_c not in ":=" and prev_c != ":" :
185191 # Same logic for : as in numeric parameters
186192 state = INSIDE_PN
187193 placeholders .append ("" )
188- elif style == "pyformat" and c == "%" and next_c == "(" :
194+ elif style == DbApiParamstyle . PYFORMAT . value and c == "%" and next_c == "(" :
189195 state = INSIDE_PN
190196 placeholders .append ("" )
191- elif style in ("format" , "pyformat" ) and c == "%" :
192- style = "format"
197+ elif style in (DbApiParamstyle . FORMAT . value , DbApiParamstyle . PYFORMAT . value ) and c == "%" :
198+ style = DbApiParamstyle . FORMAT . value
193199 if in_param_escape :
194200 in_param_escape = False
195201 output_query .append (c )
@@ -227,7 +233,7 @@ def convert_paramstyle(style: str, query) -> typing.Tuple[str, typing.Any]:
227233 output_query .append (c )
228234
229235 elif state == INSIDE_PN :
230- if style == "named" :
236+ if style == DbApiParamstyle . NAMED . value :
231237 placeholders [- 1 ] += c
232238 if next_c is None or (not next_c .isalnum () and next_c != "_" ):
233239 state = OUTSIDE
@@ -237,7 +243,7 @@ def convert_paramstyle(style: str, query) -> typing.Tuple[str, typing.Any]:
237243 del placeholders [- 1 ]
238244 except ValueError :
239245 output_query .append ("$" + str (len (placeholders )))
240- elif style == "pyformat" :
246+ elif style == DbApiParamstyle . PYFORMAT . value :
241247 if prev_c == ")" and c == "s" :
242248 state = OUTSIDE
243249 try :
@@ -250,17 +256,22 @@ def convert_paramstyle(style: str, query) -> typing.Tuple[str, typing.Any]:
250256 pass
251257 else :
252258 placeholders [- 1 ] += c
253- elif style == "format" :
259+ elif style == DbApiParamstyle . FORMAT . value :
254260 state = OUTSIDE
255261
256262 elif state == INSIDE_CO :
257263 output_query .append (c )
258264 if c == "\n " :
259265 state = OUTSIDE
260266
267+ elif state == INSIDE_MC :
268+ output_query .append (c )
269+ if c == "/" and prev_c == "*" :
270+ state = OUTSIDE
271+
261272 prev_c = c
262273
263- if style in ("numeric" , "qmark" , "format" ):
274+ if style in (DbApiParamstyle . NUMERIC . value , DbApiParamstyle . QMARK . value , DbApiParamstyle . FORMAT . value ):
264275
265276 def make_args (vals ):
266277 return vals
@@ -466,7 +477,7 @@ def __init__(
466477 self .notices : deque = deque (maxlen = 100 )
467478 self .parameter_statuses : deque = deque (maxlen = 100 )
468479 self .max_prepared_statements : int = int (max_prepared_statements )
469- self ._run_cursor : Cursor = Cursor (self , paramstyle = "named" )
480+ self ._run_cursor : Cursor = Cursor (self , paramstyle = DbApiParamstyle . NAMED . value )
470481 self ._client_protocol_version : int = client_protocol_version
471482 self ._database = database
472483 self .py_types = deepcopy (PY_TYPES )
@@ -1600,7 +1611,7 @@ def execute(self: "Connection", cursor: Cursor, operation: str, vals) -> None:
16001611 args : typing .Tuple [typing .Optional [typing .Tuple [str , typing .Any ]], ...] = ()
16011612 # transforms user provided bind parameters to server friendly bind parameters
16021613 params : typing .Tuple [typing .Optional [typing .Tuple [int , int , typing .Callable ]], ...] = ()
1603-
1614+ has_bind_parameters : bool = False if vals is None else True
16041615 # multi dimensional dictionary to store the data
16051616 # cache = self._caches[cursor.paramstyle][pid]
16061617 # cache = {'statement': {}, 'ps': {}}
@@ -1622,12 +1633,12 @@ def execute(self: "Connection", cursor: Cursor, operation: str, vals) -> None:
16221633 try :
16231634 statement , make_args = cache ["statement" ][operation ]
16241635 except KeyError :
1625- if vals :
1636+ if has_bind_parameters :
16261637 statement , make_args = cache ["statement" ][operation ] = convert_paramstyle (cursor .paramstyle , operation )
16271638 else :
16281639 # use a no-op make_args in lieu of parsing the sql statement
16291640 statement , make_args = cache ["statement" ][operation ] = operation , lambda p : ()
1630- if vals :
1641+ if has_bind_parameters :
16311642 args = make_args (vals )
16321643 # change the args to the format that the DB will identify
16331644 # take reference from self.py_types
0 commit comments