Skip to content

Commit a1c709b

Browse files
committed
Fix for CONPY-133:
Extended parser for supporting MariaDB comment syntax (https://mariadb.com/kb/en/comment-syntax/)
1 parent 6a83209 commit a1c709b

File tree

4 files changed

+91
-4
lines changed

4 files changed

+91
-4
lines changed

include/mariadb_python.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ typedef struct st_parser {
157157
char* value_ofs;
158158
enum enum_paramstyle paramstyle;
159159
MrdbString *keys;
160+
MYSQL *mysql;
160161
} MrdbParser;
161162

162163
struct mrdb_pool;
@@ -415,7 +416,7 @@ mariadb_param_update(void *data, MYSQL_BIND *bind, uint32_t row_nr);
415416

416417
/* parser prototypes */
417418
MrdbParser *
418-
MrdbParser_init(const char *statement, size_t length);
419+
MrdbParser_init(MYSQL *mysql, const char *statement, size_t length);
419420

420421
void
421422
MrdbParser_end(MrdbParser *p);

mariadb/mariadb_cursor.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
732732

733733
if (!self->parser)
734734
{
735-
self->parser= MrdbParser_init(statement, statement_len);
735+
self->parser= MrdbParser_init(self->connection->mysql, statement, statement_len);
736736
if (MrdbParser_parse(self->parser, 0, errmsg, 128))
737737
{
738738
PyErr_SetString(Mariadb_ProgrammingError, errmsg);
@@ -1364,7 +1364,7 @@ MrdbCursor_executemany(MrdbCursor *self,
13641364

13651365
if (!self->parser)
13661366
{
1367-
if (!(self->parser= MrdbParser_init(statement, (size_t)statement_len)))
1367+
if (!(self->parser= MrdbParser_init(self->connection->mysql, statement, (size_t)statement_len)))
13681368
{
13691369
exit(-1);
13701370
}

mariadb/mariadb_parser.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ MrdbParser_end(MrdbParser* p)
7373
}
7474

7575
MrdbParser *
76-
MrdbParser_init(const char *statement, size_t length)
76+
MrdbParser_init(MYSQL *mysql, const char *statement, size_t length)
7777
{
7878
MrdbParser *p;
7979

@@ -91,6 +91,7 @@ MrdbParser_init(const char *statement, size_t length)
9191
}
9292
memcpy(p->statement.str, statement, length);
9393
p->statement.length= length;
94+
p->mysql= mysql;
9495
}
9596
return p;
9697
}
@@ -155,6 +156,48 @@ MrdbParser_parse(MrdbParser *p, uint8_t is_batch,
155156
if (*a == '/' && *(a + 1) == '*')
156157
{
157158
a+= 2;
159+
if (a+1 < end && *a == '!')
160+
{
161+
/* check special syntax: 1. comment followed by '!' and whitespace */
162+
if (isspace(*(a+1)))
163+
{
164+
a+= 2;
165+
continue;
166+
}
167+
/* check special syntax: 3. comment followed by '!' 5 or 6 digit version number */
168+
if (a + 7 < end && isdigit(*(a+1)))
169+
{
170+
char *x;
171+
ulong version_number= strtol(a+1, &x, 10);
172+
a= x;
173+
if ((version_number >= 50700 && version_number <= 99999) ||
174+
!(version_number <= mysql_get_server_version(p->mysql)))
175+
{
176+
p->in_comment= 1;
177+
}
178+
continue;
179+
}
180+
}
181+
if (a+2 < end && *a == 'M' && *(a+1) == '!')
182+
{
183+
a+= 2;
184+
/* check special syntax: 2. comment followed by 'M! ' (MariaDB only) */
185+
if (isspace(*(a)))
186+
continue;
187+
188+
/* check special syntax: 2. comment followed by 'M!' and version number */
189+
if (a + 6 < end && isdigit(*a))
190+
{
191+
char *x;
192+
ulong version_number= strtol(a, &x, 10);
193+
a= x;
194+
if (!(version_number <= mysql_get_server_version(p->mysql)))
195+
{
196+
p->in_comment= 1;
197+
}
198+
continue;
199+
}
200+
}
158201
p->in_comment= 1;
159202
continue;
160203
}

testing/test/integration/test_cursor.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,49 @@ def test_conpy129(self):
10921092
self.assertEqual(conn.server_version_info, (major, minor, patch))
10931093
self.assertEqual(conn.get_server_version(), (major, minor, patch))
10941094

1095+
def test_conpy133(self):
1096+
if is_mysql():
1097+
self.skipTest("Skip (MySQL)")
1098+
conn= create_connection()
1099+
1100+
cursor= conn.cursor()
1101+
cursor.execute("SELECT /*! ? */", (1,))
1102+
row= cursor.fetchone()
1103+
self.assertEqual(row[0], 1)
1104+
del cursor
1105+
1106+
cursor= conn.cursor()
1107+
cursor.execute("SELECT /*M! ? */", (1,))
1108+
row= cursor.fetchone()
1109+
self.assertEqual(row[0], 1)
1110+
del cursor
1111+
1112+
cursor= conn.cursor()
1113+
cursor.execute("SELECT /*M!50601 ? */", (1,))
1114+
row= cursor.fetchone()
1115+
self.assertEqual(row[0], 1)
1116+
del cursor
1117+
1118+
cursor= conn.cursor()
1119+
cursor.execute("SELECT /*!40301 ? */", (1,))
1120+
row= cursor.fetchone()
1121+
self.assertEqual(row[0], 1)
1122+
del cursor
1123+
1124+
cursor= conn.cursor()
1125+
try:
1126+
cursor.execute("SELECT /*!50701 ? */", (1,))
1127+
except mariadb.DataError:
1128+
pass
1129+
del cursor
1130+
1131+
cursor= conn.cursor()
1132+
try:
1133+
cursor.execute("SELECT /*!250701 ? */", (1,))
1134+
except mariadb.DataError:
1135+
pass
1136+
del cursor
1137+
10951138
def test_conpy91(self):
10961139
with create_connection() as connection:
10971140
with connection.cursor() as cursor:

0 commit comments

Comments
 (0)