27
27
#define PDO_PARSER_TEXT 1
28
28
#define PDO_PARSER_BIND 2
29
29
#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
31
34
32
35
#define RET (i ) {s->cur = cursor; return i; }
33
36
#define SKIP_ONE (i ) {s->cur = s->tok + 1; return i; }
@@ -47,11 +50,11 @@ static int scan(Scanner *s)
47
50
char * cursor = s -> cur ;
48
51
49
52
s -> tok = cursor ;
50
- #line 55 "ext/pdo/pdo_sql_parser.re"
53
+ #line 59 "ext/pdo/pdo_sql_parser.re"
51
54
52
55
53
56
54
- #line 55 "ext/pdo/pdo_sql_parser.c"
57
+ #line 58 "ext/pdo/pdo_sql_parser.c"
55
58
{
56
59
YYCTYPE yych ;
57
60
@@ -80,9 +83,9 @@ static int scan(Scanner *s)
80
83
yych = * (YYMARKER = ++ YYCURSOR );
81
84
if (yych >= 0x01 ) goto yy37 ;
82
85
yy4 :
83
- #line 63 "ext/pdo/pdo_sql_parser.re"
86
+ #line 68 "ext/pdo/pdo_sql_parser.re"
84
87
{ SKIP_ONE (PDO_PARSER_TEXT ); }
85
- #line 86 "ext/pdo/pdo_sql_parser.c"
88
+ #line 89 "ext/pdo/pdo_sql_parser.c"
86
89
yy5 :
87
90
yych = * (YYMARKER = ++ YYCURSOR );
88
91
if (yych <= 0x00 ) goto yy4 ;
@@ -152,8 +155,8 @@ static int scan(Scanner *s)
152
155
case 'w' :
153
156
case 'x' :
154
157
case 'y' :
155
- case 'z' : goto yy26 ;
156
- case ':' : goto yy29 ;
158
+ case 'z' : goto yy25 ;
159
+ case ':' : goto yy28 ;
157
160
default : goto yy4 ;
158
161
}
159
162
yy7 :
@@ -163,9 +166,9 @@ static int scan(Scanner *s)
163
166
default : goto yy8 ;
164
167
}
165
168
yy8 :
166
- #line 62 "ext/pdo/pdo_sql_parser.re"
169
+ #line 67 "ext/pdo/pdo_sql_parser.re"
167
170
{ RET (PDO_PARSER_BIND_POS ); }
168
- #line 169 "ext/pdo/pdo_sql_parser.c"
171
+ #line 172 "ext/pdo/pdo_sql_parser.c"
169
172
yy9 :
170
173
yych = * ++ YYCURSOR ;
171
174
goto yy4 ;
@@ -202,9 +205,9 @@ static int scan(Scanner *s)
202
205
default : goto yy12 ;
203
206
}
204
207
yy14 :
205
- #line 65 "ext/pdo/pdo_sql_parser.re"
208
+ #line 70 "ext/pdo/pdo_sql_parser.re"
206
209
{ RET (PDO_PARSER_TEXT ); }
207
- #line 208 "ext/pdo/pdo_sql_parser.c"
210
+ #line 211 "ext/pdo/pdo_sql_parser.c"
208
211
yy15 :
209
212
++ YYCURSOR ;
210
213
if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
@@ -225,9 +228,9 @@ static int scan(Scanner *s)
225
228
yy19 :
226
229
++ YYCURSOR ;
227
230
yy20 :
228
- #line 64 "ext/pdo/pdo_sql_parser.re"
231
+ #line 69 "ext/pdo/pdo_sql_parser.re"
229
232
{ RET (PDO_PARSER_TEXT ); }
230
- #line 231 "ext/pdo/pdo_sql_parser.c"
233
+ #line 234 "ext/pdo/pdo_sql_parser.c"
231
234
yy21 :
232
235
++ YYCURSOR ;
233
236
if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
@@ -239,17 +242,10 @@ static int scan(Scanner *s)
239
242
}
240
243
yy23 :
241
244
++ 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"
248
248
yy25 :
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 :
253
249
++ YYCURSOR ;
254
250
if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
255
251
yych = * YYCURSOR ;
@@ -316,21 +312,25 @@ static int scan(Scanner *s)
316
312
case 'w' :
317
313
case 'x' :
318
314
case 'y' :
319
- case 'z' : goto yy26 ;
320
- default : goto yy28 ;
315
+ case 'z' : goto yy25 ;
316
+ default : goto yy27 ;
321
317
}
322
- yy28 :
323
- #line 61 "ext/pdo/pdo_sql_parser.re"
318
+ yy27 :
319
+ #line 66 "ext/pdo/pdo_sql_parser.re"
324
320
{ 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 :
327
323
++ YYCURSOR ;
328
324
if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
329
325
yych = * YYCURSOR ;
330
326
switch (yych ) {
331
- case ':' : goto yy29 ;
332
- default : goto yy25 ;
327
+ case ':' : goto yy28 ;
328
+ default : goto yy30 ;
333
329
}
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"
334
334
yy31 :
335
335
++ YYCURSOR ;
336
336
if (YYLIMIT <= YYCURSOR ) YYFILL (1 );
@@ -350,7 +350,7 @@ static int scan(Scanner *s)
350
350
goto yy31 ;
351
351
yy34 :
352
352
++ YYCURSOR ;
353
- #line 59 "ext/pdo/pdo_sql_parser.re"
353
+ #line 63 "ext/pdo/pdo_sql_parser.re"
354
354
{ RET (PDO_PARSER_TEXT ); }
355
355
#line 356 "ext/pdo/pdo_sql_parser.c"
356
356
yy36 :
@@ -372,11 +372,11 @@ static int scan(Scanner *s)
372
372
goto yy36 ;
373
373
yy39 :
374
374
++ YYCURSOR ;
375
- #line 58 "ext/pdo/pdo_sql_parser.re"
375
+ #line 62 "ext/pdo/pdo_sql_parser.re"
376
376
{ RET (PDO_PARSER_TEXT ); }
377
377
#line 378 "ext/pdo/pdo_sql_parser.c"
378
378
}
379
- #line 66 "ext/pdo/pdo_sql_parser.re"
379
+ #line 71 "ext/pdo/pdo_sql_parser.re"
380
380
381
381
}
382
382
@@ -401,7 +401,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
401
401
char * ptr , * newbuffer ;
402
402
int t ;
403
403
uint32_t bindno = 0 ;
404
- int ret = 0 ;
404
+ int ret = 0 , escapes = 0 ;
405
405
size_t newbuffer_len ;
406
406
HashTable * params ;
407
407
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
414
414
415
415
/* phase 1: look for args */
416
416
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
+
418
423
if (t == PDO_PARSER_BIND ) {
419
424
int len = s .cur - s .tok ;
420
425
if ((inquery < (s .cur - len )) && isalnum (* (s .cur - len - 1 ))) {
421
426
continue ;
422
427
}
423
428
query_type |= PDO_PLACEHOLDER_NAMED ;
424
- } else {
429
+ } else if ( t == PDO_PARSER_BIND_POS ) {
425
430
query_type |= PDO_PLACEHOLDER_POSITIONAL ;
426
431
}
427
432
@@ -430,7 +435,16 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
430
435
plc -> next = NULL ;
431
436
plc -> pos = s .tok ;
432
437
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
+ }
434
448
435
449
if (placetail ) {
436
450
placetail -> next = plc ;
@@ -441,7 +455,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
441
455
}
442
456
}
443
457
444
- if (bindno == 0 ) {
458
+ if (! placeholders ) {
445
459
/* nothing to do; good! */
446
460
return 0 ;
447
461
}
@@ -456,11 +470,11 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
456
470
457
471
if (stmt -> supports_placeholders == query_type && !stmt -> named_rewrite_template ) {
458
472
/* query matches native syntax */
459
- ret = 0 ;
460
- goto clean_up ;
473
+ newbuffer_len = inquery_len ;
474
+ goto rewrite ;
461
475
}
462
476
463
- if (stmt -> named_rewrite_template ) {
477
+ if (query_type == PDO_PLACEHOLDER_NAMED && stmt -> named_rewrite_template ) {
464
478
/* magic/hack.
465
479
* We we pretend that the query was positional even if
466
480
* 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
471
485
472
486
params = stmt -> bound_params ;
473
487
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 )) {
482
489
/* extra bit of validation for instances when same params are bound more than once */
483
490
if (query_type != PDO_PLACEHOLDER_POSITIONAL && bindno > zend_hash_num_elements (params )) {
484
491
int ok = 1 ;
@@ -504,7 +511,16 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
504
511
newbuffer_len = inquery_len ;
505
512
506
513
/* 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
+
508
524
if (query_type == PDO_PLACEHOLDER_POSITIONAL ) {
509
525
param = zend_hash_index_find_ptr (params , plc -> bindno );
510
526
} else {
@@ -618,7 +634,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
618
634
619
635
rewrite :
620
636
/* allocate output buffer */
621
- newbuffer = emalloc (newbuffer_len + 1 );
637
+ newbuffer = emalloc (newbuffer_len - escapes + 1 );
622
638
* outquery = newbuffer ;
623
639
624
640
/* and build the query */
@@ -631,8 +647,13 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
631
647
memcpy (newbuffer , ptr , t );
632
648
newbuffer += t ;
633
649
}
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
+ }
636
657
ptr = plc -> pos + plc -> len ;
637
658
638
659
plc = plc -> next ;
@@ -665,6 +686,11 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, size_t inquery_len
665
686
for (plc = placeholders ; plc ; plc = plc -> next ) {
666
687
int skip_map = 0 ;
667
688
char * p ;
689
+
690
+ if (plc -> bindno == PDO_PARSER_BINDNO_ESCAPED_CHAR ) {
691
+ continue ;
692
+ }
693
+
668
694
name = estrndup (plc -> pos , plc -> len );
669
695
670
696
/* 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
710
736
efree (name );
711
737
plc -> quoted = "?" ;
712
738
plc -> qlen = 1 ;
739
+ newbuffer_len -= plc -> len - 1 ;
713
740
}
714
741
715
742
goto rewrite ;
0 commit comments