77
88import re
99
10+ from lib .core .common import Backend
11+ from lib .core .enums import DBMS
1012from lib .core .enums import PRIORITY
1113
1214__priority__ = PRIORITY .NORMAL
@@ -43,7 +45,16 @@ def _unwrapIsnull(query):
4345 break
4446
4547 inner = retVal [match .end ():end ]
46- separator = inner .rfind (',' )
48+ separator , depth = - 1 , 0 # the argument separator is the comma at the top level
49+
50+ for index , char in enumerate (inner ):
51+ if char == '(' :
52+ depth += 1
53+ elif char == ')' :
54+ depth -= 1
55+ elif char == ',' and depth == 0 :
56+ separator = index
57+
4758 if separator < 1 :
4859 break
4960
@@ -75,6 +86,11 @@ def _reshape(payload, opener, tail, build):
7586 pos = pos + match .end ()
7687 continue
7788 replacement = build (query , rest )
89+
90+ if replacement is None : # builder declined, leave this occurrence alone
91+ pos = pos + match .end ()
92+ continue
93+
7894 retVal = retVal [:start ] + replacement + retVal [end + 1 + rest .end ():]
7995 pos = start + len (replacement )
8096 return retVal
@@ -134,7 +150,12 @@ def _mysql(query, rest):
134150 def _mysqlSet (query , rest ):
135151 # set-membership form of the same read ('... IN (<ordinals>)', used by the Huffman retrieval).
136152 # ORD('') is 0, so a past-the-end position matches the ordinal 0, which is the empty string here
137- position , ordinals = rest .group (1 ), [int (_ ) for _ in rest .group (2 ).split (',' )]
153+ position = rest .group (1 )
154+ ordinals = [int (_ ) for _ in rest .group (2 ).split (',' ) if _ .strip ().isdigit ()]
155+
156+ if not ordinals or any (_ > 255 for _ in ordinals ): # a byte comparison cannot represent those
157+ return None
158+
138159 query = _unwrapIsnull (query )
139160 members = "," .join ("''" if _ == 0 else "0x%02x" % _ for _ in ordinals )
140161 return "BINARY RIGHT(LEFT(%s,%s),(%s<=LENGTH(CONVERT(%s USING ascii)))) IN (%s)" % (query , position , position , query , members )
@@ -150,7 +171,9 @@ def _mssql(query, rest):
150171 comma_tail = r"\s*,\s*(\d+)\s*,\s*1\)\)\s*(>=|<=|>|<|=)\s*(\d+)"
151172 set_tail = r"\s*,\s*(\d+)\s*,\s*1\)\)\s+IN\s*\(([\d,\s]+)\)"
152173
153- if re .search (r"(?i)IFNULL\(" , payload ): # also on payloads that are not single-character reads
174+ # also on payloads that are not single-character reads. Gated on MySQL, because IFNULL() is used
175+ # by H2, HSQLDB, Cubrid and others too, and IF() is not a function there
176+ if Backend .getIdentifiedDbms () == DBMS .MYSQL and re .search (r"(?i)IFNULL\(" , payload ):
154177 payload = _unwrapIsnull (payload )
155178
156179 retVal = _reshape (payload , r"(?i)ORD\(MID\(" , set_tail , _mysqlSet )
0 commit comments