2727#define PDO_PARSER_TEXT 1
2828#define PDO_PARSER_BIND 2
2929#define PDO_PARSER_BIND_POS 3
30- #define PDO_PARSER_EOI 4
30+ #define PDO_PARSER_ESCAPED_QUESTION 4
31+ #define PDO_PARSER_EOI 5
32+
33+ #define PDO_PARSER_BINDNO_ESCAPED_CHAR -1
3134
3235#define RET (i ) {s->cur = cursor; return i; }
3336#define SKIP_ONE (i ) {s->cur = s->tok + 1; return i; }
@@ -47,11 +50,11 @@ static int scan(Scanner *s)
4750 char * cursor = s -> cur ;
4851
4952 s -> tok = cursor ;
50- #line 55 "ext/pdo/pdo_sql_parser.re"
53+ #line 59 "ext/pdo/pdo_sql_parser.re"
5154
5255
5356
54- #line 55 "ext/pdo/pdo_sql_parser.c"
57+ #line 58 "ext/pdo/pdo_sql_parser.c"
5558{
5659 YYCTYPE yych ;
5760
@@ -80,9 +83,9 @@ static int scan(Scanner *s)
8083 yych = * (YYMARKER = ++ YYCURSOR );
8184 if (yych >= 0x01 ) goto yy37 ;
8285yy4 :
83- #line 63 "ext/pdo/pdo_sql_parser.re"
86+ #line 68 "ext/pdo/pdo_sql_parser.re"
8487 { SKIP_ONE (PDO_PARSER_TEXT ); }
85- #line 86 "ext/pdo/pdo_sql_parser.c"
88+ #line 89 "ext/pdo/pdo_sql_parser.c"
8689yy5 :
8790 yych = * (YYMARKER = ++ YYCURSOR );
8891 if (yych <= 0x00 ) goto yy4 ;
@@ -152,8 +155,8 @@ static int scan(Scanner *s)
152155 case 'w' :
153156 case 'x' :
154157 case 'y' :
155- case 'z' : goto yy26 ;
156- case ':' : goto yy29 ;
158+ case 'z' : goto yy25 ;
159+ case ':' : goto yy28 ;
157160 default : goto yy4 ;
158161 }
159162yy7 :
@@ -163,9 +166,9 @@ static int scan(Scanner *s)
163166 default : goto yy8 ;
164167 }
165168yy8 :
166- #line 62 "ext/pdo/pdo_sql_parser.re"
169+ #line 67 "ext/pdo/pdo_sql_parser.re"
167170 { RET (PDO_PARSER_BIND_POS ); }
168- #line 169 "ext/pdo/pdo_sql_parser.c"
171+ #line 172 "ext/pdo/pdo_sql_parser.c"
169172yy9 :
170173 yych = * ++ YYCURSOR ;
171174 goto yy4 ;
@@ -202,9 +205,9 @@ static int scan(Scanner *s)
202205 default : goto yy12 ;
203206 }
204207yy14 :
205- #line 65 "ext/pdo/pdo_sql_parser.re"
208+ #line 70 "ext/pdo/pdo_sql_parser.re"
206209 { RET (PDO_PARSER_TEXT ); }
207- #line 208 "ext/pdo/pdo_sql_parser.c"
210+ #line 211 "ext/pdo/pdo_sql_parser.c"
208211yy15 :
209212 ++ YYCURSOR ;
210213 if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
@@ -225,9 +228,9 @@ static int scan(Scanner *s)
225228yy19 :
226229 ++ YYCURSOR ;
227230yy20 :
228- #line 64 "ext/pdo/pdo_sql_parser.re"
231+ #line 69 "ext/pdo/pdo_sql_parser.re"
229232 { RET (PDO_PARSER_TEXT ); }
230- #line 231 "ext/pdo/pdo_sql_parser.c"
233+ #line 234 "ext/pdo/pdo_sql_parser.c"
231234yy21 :
232235 ++ YYCURSOR ;
233236 if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
@@ -239,17 +242,10 @@ static int scan(Scanner *s)
239242 }
240243yy23 :
241244 ++ YYCURSOR ;
242- if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
243- yych = * YYCURSOR ;
244- switch (yych ) {
245- case '?' : goto yy23 ;
246- default : goto yy25 ;
247- }
245+ #line 65 "ext/pdo/pdo_sql_parser.re"
246+ { RET (PDO_PARSER_ESCAPED_QUESTION ); }
247+ #line 248 "ext/pdo/pdo_sql_parser.c"
248248yy25 :
249- #line 60 "ext/pdo/pdo_sql_parser.re"
250- { RET (PDO_PARSER_TEXT ); }
251- #line 252 "ext/pdo/pdo_sql_parser.c"
252- yy26 :
253249 ++ YYCURSOR ;
254250 if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
255251 yych = * YYCURSOR ;
@@ -316,21 +312,25 @@ static int scan(Scanner *s)
316312 case 'w' :
317313 case 'x' :
318314 case 'y' :
319- case 'z' : goto yy26 ;
320- default : goto yy28 ;
315+ case 'z' : goto yy25 ;
316+ default : goto yy27 ;
321317 }
322- yy28 :
323- #line 61 "ext/pdo/pdo_sql_parser.re"
318+ yy27 :
319+ #line 66 "ext/pdo/pdo_sql_parser.re"
324320 { RET (PDO_PARSER_BIND ); }
325- #line 326 "ext/pdo/pdo_sql_parser.c"
326- yy29 :
321+ #line 322 "ext/pdo/pdo_sql_parser.c"
322+ yy28 :
327323 ++ YYCURSOR ;
328324 if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
329325 yych = * YYCURSOR ;
330326 switch (yych ) {
331- case ':' : goto yy29 ;
332- default : goto yy25 ;
327+ case ':' : goto yy28 ;
328+ default : goto yy30 ;
333329 }
330+ yy30 :
331+ #line 64 "ext/pdo/pdo_sql_parser.re"
332+ { RET (PDO_PARSER_TEXT ); }
333+ #line 334 "ext/pdo/pdo_sql_parser.c"
334334yy31 :
335335 ++ YYCURSOR ;
336336 if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
@@ -350,7 +350,7 @@ static int scan(Scanner *s)
350350 goto yy31 ;
351351yy34 :
352352 ++ YYCURSOR ;
353- #line 59 "ext/pdo/pdo_sql_parser.re"
353+ #line 63 "ext/pdo/pdo_sql_parser.re"
354354 { RET (PDO_PARSER_TEXT ); }
355355#line 356 "ext/pdo/pdo_sql_parser.c"
356356yy36 :
@@ -372,11 +372,11 @@ static int scan(Scanner *s)
372372 goto yy36 ;
373373yy39 :
374374 ++ YYCURSOR ;
375- #line 58 "ext/pdo/pdo_sql_parser.re"
375+ #line 62 "ext/pdo/pdo_sql_parser.re"
376376 { RET (PDO_PARSER_TEXT ); }
377377#line 378 "ext/pdo/pdo_sql_parser.c"
378378}
379- #line 66 "ext/pdo/pdo_sql_parser.re"
379+ #line 71 "ext/pdo/pdo_sql_parser.re"
380380
381381}
382382
@@ -401,7 +401,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
401401 char * ptr , * newbuffer ;
402402 int t ;
403403 uint32_t bindno = 0 ;
404- int ret = 0 ;
404+ int ret = 0 , escapes = 0 ;
405405 size_t newbuffer_len ;
406406 HashTable * params ;
407407 struct pdo_bound_param_data * param ;
@@ -414,14 +414,19 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
414414
415415 /* phase 1: look for args */
416416 while ((t = scan (& s )) != PDO_PARSER_EOI ) {
417- if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS ) {
417+ if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS || t == PDO_PARSER_ESCAPED_QUESTION ) {
418+ if (t == PDO_PARSER_ESCAPED_QUESTION && stmt -> supports_placeholders == PDO_PLACEHOLDER_POSITIONAL ) {
419+ /* escaped question marks unsupported, treat as text */
420+ continue ;
421+ }
422+
418423 if (t == PDO_PARSER_BIND ) {
419424 int len = s .cur - s .tok ;
420425 if ((inquery < (s .cur - len )) && isalnum (* (s .cur - len - 1 ))) {
421426 continue ;
422427 }
423428 query_type |= PDO_PLACEHOLDER_NAMED ;
424- } else {
429+ } else if ( t == PDO_PARSER_BIND_POS ) {
425430 query_type |= PDO_PLACEHOLDER_POSITIONAL ;
426431 }
427432
@@ -430,7 +435,16 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
430435 plc -> next = NULL ;
431436 plc -> pos = s .tok ;
432437 plc -> len = s .cur - s .tok ;
433- plc -> bindno = bindno ++ ;
438+
439+ if (t == PDO_PARSER_ESCAPED_QUESTION ) {
440+ plc -> bindno = PDO_PARSER_BINDNO_ESCAPED_CHAR ;
441+ plc -> quoted = "?" ;
442+ plc -> qlen = 1 ;
443+ plc -> freeq = 0 ;
444+ escapes ++ ;
445+ } else {
446+ plc -> bindno = bindno ++ ;
447+ }
434448
435449 if (placetail ) {
436450 placetail -> next = plc ;
@@ -441,7 +455,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
441455 }
442456 }
443457
444- if (bindno == 0 ) {
458+ if (! placeholders ) {
445459 /* nothing to do; good! */
446460 return 0 ;
447461 }
@@ -456,11 +470,11 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
456470
457471 if (stmt -> supports_placeholders == query_type && !stmt -> named_rewrite_template ) {
458472 /* query matches native syntax */
459- ret = 0 ;
460- goto clean_up ;
473+ newbuffer_len = inquery_len ;
474+ goto rewrite ;
461475 }
462476
463- if (stmt -> named_rewrite_template ) {
477+ if (query_type == PDO_PLACEHOLDER_NAMED && stmt -> named_rewrite_template ) {
464478 /* magic/hack.
465479 * We we pretend that the query was positional even if
466480 * it was named so that we fall into the
@@ -471,14 +485,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
471485
472486 params = stmt -> bound_params ;
473487
474- /* Do we have placeholders but no bound params */
475- if (bindno && !params && stmt -> supports_placeholders == PDO_PLACEHOLDER_NONE ) {
476- pdo_raise_impl_error (stmt -> dbh , stmt , "HY093" , "no parameters were bound" );
477- ret = -1 ;
478- goto clean_up ;
479- }
480-
481- if (params && bindno != zend_hash_num_elements (params ) && stmt -> supports_placeholders == PDO_PLACEHOLDER_NONE ) {
488+ if (bindno && stmt -> supports_placeholders == PDO_PLACEHOLDER_NONE && params && bindno != zend_hash_num_elements (params )) {
482489 /* extra bit of validation for instances when same params are bound more than once */
483490 if (query_type != PDO_PLACEHOLDER_POSITIONAL && bindno > zend_hash_num_elements (params )) {
484491 int ok = 1 ;
@@ -504,7 +511,16 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
504511 newbuffer_len = inquery_len ;
505512
506513 /* let's quote all the values */
507- for (plc = placeholders ; plc ; plc = plc -> next ) {
514+ for (plc = placeholders ; plc && params ; plc = plc -> next ) {
515+ if (plc -> bindno == PDO_PARSER_BINDNO_ESCAPED_CHAR ) {
516+ /* escaped character */
517+ continue ;
518+ }
519+
520+ if (query_type == PDO_PLACEHOLDER_NONE ) {
521+ continue ;
522+ }
523+
508524 if (query_type == PDO_PLACEHOLDER_POSITIONAL ) {
509525 param = zend_hash_index_find_ptr (params , plc -> bindno );
510526 } else {
@@ -618,7 +634,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
618634
619635rewrite :
620636 /* allocate output buffer */
621- newbuffer = emalloc (newbuffer_len + 1 );
637+ newbuffer = emalloc (newbuffer_len - escapes + 1 );
622638 * outquery = newbuffer ;
623639
624640 /* and build the query */
@@ -631,8 +647,13 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
631647 memcpy (newbuffer , ptr , t );
632648 newbuffer += t ;
633649 }
634- memcpy (newbuffer , plc -> quoted , plc -> qlen );
635- newbuffer += plc -> qlen ;
650+ if (plc -> quoted ) {
651+ memcpy (newbuffer , plc -> quoted , plc -> qlen );
652+ newbuffer += plc -> qlen ;
653+ } else {
654+ memcpy (newbuffer , plc -> pos , plc -> len );
655+ newbuffer += plc -> len ;
656+ }
636657 ptr = plc -> pos + plc -> len ;
637658
638659 plc = plc -> next ;
@@ -665,6 +686,11 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
665686 for (plc = placeholders ; plc ; plc = plc -> next ) {
666687 int skip_map = 0 ;
667688 char * p ;
689+
690+ if (plc -> bindno == PDO_PARSER_BINDNO_ESCAPED_CHAR ) {
691+ continue ;
692+ }
693+
668694 name = estrndup (plc -> pos , plc -> len );
669695
670696 /* check if bound parameter is already available */
@@ -710,6 +736,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
710736 efree (name );
711737 plc -> quoted = "?" ;
712738 plc -> qlen = 1 ;
739+ newbuffer_len -= plc -> len - 1 ;
713740 }
714741
715742 goto rewrite ;
0 commit comments