Details
-
Bug
-
Status: Closed (View Workflow)
-
Minor
-
Resolution: Fixed
-
1.1.14
-
None
-
3.12.12
Description
Hi Developers,
using version 1.1.14 of the connector some literals present into an SQL statement are not correctly parsed, causing a syntax error on application side because any qestion mark (qmark) present after the literal is ignored. For example, the following statement:
SELECT value FROM mytable WHERE lower(convert(trim(BOTH '"' FROM convert(value, CHAR)) using utf8mb4)) LIKE lower(?) |
is not correctly understood, leaving the qmark not identified. Investigating further this issue, I observed that the logic used to early identify the start of the literals doesn't manage well the literal of above statement, because it has a single double quote between two single quotes. In other words, the literal itself is a single double quote. Other more complex testing statements can be provided.
Given that this issue was blocking for my use case, I quickly fixed it using the following logic:
diff --git a/include/mariadb_python.h b/include/mariadb_python.h
|
index bb2a24d..be753a2 100755
|
--- a/include/mariadb_python.h
|
+++ b/include/mariadb_python.h
|
@@ -224,7 +224,6 @@ typedef struct st_ext_field_type { |
typedef struct st_parser { |
MrdbString statement;
|
MrdbString *keys;
|
- uint8_t in_literal[3];
|
uint8_t in_comment;
|
uint8_t in_values;
|
uint8_t is_insert;
|
diff --git a/mariadb/mariadb_parser.c b/mariadb/mariadb_parser.c
|
index 25fa17b..a3d0caf 100755
|
--- a/mariadb/mariadb_parser.c
|
+++ b/mariadb/mariadb_parser.c
|
@@ -18,11 +18,9 @@
|
****************************************************************************/
|
|
#include <mariadb_python.h>
|
+#include <stdbool.h>
|
|
#define IS_WHITESPACE(a) (a==32 || a==9 || a==10 || a==13)
|
-#define IN_LITERAL(p) ((p)->in_literal[0] ||\
|
- (p)->in_literal[1] ||\
|
- (p)->in_literal[2])
|
|
const char *comment_start= "/*"; |
const char *comment_end= "*/"; |
@@ -130,6 +128,8 @@ MrdbParser_parse(MrdbParser *p, uint8_t is_batch,
|
char *a, *end; |
char lastchar= 0; |
uint8_t i;
|
+ bool literal_string = false; |
+ char literal_start_char = '\0'; |
|
if (errmsg_len) |
*errmsg= 0;
|
@@ -151,25 +151,33 @@ MrdbParser_parse(MrdbParser *p, uint8_t is_batch,
|
while (a <= end) |
{
|
cont:
|
-/* if (isutf8(*a)) { |
- a++;
|
- continue;
|
- } */
|
/* check literals */ |
- for (i=0; i < 3; i++) |
- {
|
- if (*a == literals[i]) |
- {
|
- p->in_literal[i]= !(p->in_literal[i]);
|
- a++;
|
- goto cont; |
+ if (!literal_string) { |
+ for (i=0; i < 3; i++) { |
+ if (*a == literals[i]) { |
+ literal_string = true; |
+ literal_start_char = *a;
|
+ a++;
|
+ goto cont; |
+ }
|
}
|
}
|
/* nothing to do, if we are inside a comment or literal */ |
- if (IN_LITERAL(p)) |
- {
|
- a++;
|
- continue; |
+ if (literal_string) { |
+ if (*a == '\\' && a+1 < end) { |
+ for (i=0; i < 3; i++) { |
+ if (*a == literals[i]) { |
+ a++; // Skip backslash |
+ }
|
+ }
|
+ }
|
+
|
+ if (*a == literal_start_char && (a == 0 || *(a-1) != '\\')) { |
+ // End of string found (not escaped) |
+ literal_string = false; |
+ literal_start_char = '\0'; |
+ goto cont; |
+ }
|
}
|
/* check comment */ |
if (!p->in_comment) |
Can you have a review of this issue and, if confirmed, evaluate if a similar fix can be added to MariaDB Python connector?
Thanks
Max