xref: /PHP-5.5/ext/pdo/pdo_sql_parser.c (revision 73c1be26)
1 /* Generated by re2c 0.13.5 */
2 #line 1 "ext/pdo/pdo_sql_parser.re"
3 /*
4   +----------------------------------------------------------------------+
5   | PHP Version 5                                                        |
6   +----------------------------------------------------------------------+
7   | Copyright (c) 1997-2015 The PHP Group                                |
8   +----------------------------------------------------------------------+
9   | This source file is subject to version 3.01 of the PHP license,      |
10   | that is bundled with this package in the file LICENSE, and is        |
11   | available through the world-wide-web at the following url:           |
12   | http://www.php.net/license/3_01.txt                                  |
13   | If you did not receive a copy of the PHP license and are unable to   |
14   | obtain it through the world-wide-web, please send a note to          |
15   | license@php.net so we can mail you a copy immediately.               |
16   +----------------------------------------------------------------------+
17   | Author: George Schlossnagle <george@omniti.com>                      |
18   +----------------------------------------------------------------------+
19 */
20 
21 /* $Id$ */
22 
23 #include "php.h"
24 #include "php_pdo_driver.h"
25 #include "php_pdo_int.h"
26 
27 #define PDO_PARSER_TEXT 1
28 #define PDO_PARSER_BIND 2
29 #define PDO_PARSER_BIND_POS 3
30 #define PDO_PARSER_EOI 4
31 
32 #define RET(i) {s->cur = cursor; return i; }
33 #define SKIP_ONE(i) {s->cur = s->tok + 1; return i; }
34 
35 #define YYCTYPE         unsigned char
36 #define YYCURSOR        cursor
37 #define YYLIMIT         s->end
38 #define YYMARKER        s->ptr
39 #define YYFILL(n)		{ RET(PDO_PARSER_EOI); }
40 
41 typedef struct Scanner {
42 	char 	*ptr, *cur, *tok, *end;
43 } Scanner;
44 
scan(Scanner * s)45 static int scan(Scanner *s)
46 {
47 	char *cursor = s->cur;
48 
49 	s->tok = cursor;
50 	#line 55 "ext/pdo/pdo_sql_parser.re"
51 
52 
53 
54 #line 55 "ext/pdo/pdo_sql_parser.c"
55 {
56 	YYCTYPE yych;
57 	unsigned int yyaccept = 0;
58 
59 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
60 	yych = *YYCURSOR;
61 	switch (yych) {
62 	case 0x00:	goto yy2;
63 	case '"':	goto yy3;
64 	case '\'':	goto yy5;
65 	case '-':	goto yy11;
66 	case '/':	goto yy9;
67 	case ':':	goto yy6;
68 	case '?':	goto yy7;
69 	default:	goto yy12;
70 	}
71 yy2:
72 	YYCURSOR = YYMARKER;
73 	switch (yyaccept) {
74 	case 0: 	goto yy4;
75 	case 1: 	goto yy10;
76 	}
77 yy3:
78 	yyaccept = 0;
79 	yych = *(YYMARKER = ++YYCURSOR);
80 	if (yych >= 0x01) goto yy43;
81 yy4:
82 #line 63 "ext/pdo/pdo_sql_parser.re"
83 	{ SKIP_ONE(PDO_PARSER_TEXT); }
84 #line 85 "ext/pdo/pdo_sql_parser.c"
85 yy5:
86 	yyaccept = 0;
87 	yych = *(YYMARKER = ++YYCURSOR);
88 	if (yych <= 0x00) goto yy4;
89 	goto yy38;
90 yy6:
91 	yych = *++YYCURSOR;
92 	switch (yych) {
93 	case '0':
94 	case '1':
95 	case '2':
96 	case '3':
97 	case '4':
98 	case '5':
99 	case '6':
100 	case '7':
101 	case '8':
102 	case '9':
103 	case 'A':
104 	case 'B':
105 	case 'C':
106 	case 'D':
107 	case 'E':
108 	case 'F':
109 	case 'G':
110 	case 'H':
111 	case 'I':
112 	case 'J':
113 	case 'K':
114 	case 'L':
115 	case 'M':
116 	case 'N':
117 	case 'O':
118 	case 'P':
119 	case 'Q':
120 	case 'R':
121 	case 'S':
122 	case 'T':
123 	case 'U':
124 	case 'V':
125 	case 'W':
126 	case 'X':
127 	case 'Y':
128 	case 'Z':
129 	case '_':
130 	case 'a':
131 	case 'b':
132 	case 'c':
133 	case 'd':
134 	case 'e':
135 	case 'f':
136 	case 'g':
137 	case 'h':
138 	case 'i':
139 	case 'j':
140 	case 'k':
141 	case 'l':
142 	case 'm':
143 	case 'n':
144 	case 'o':
145 	case 'p':
146 	case 'q':
147 	case 'r':
148 	case 's':
149 	case 't':
150 	case 'u':
151 	case 'v':
152 	case 'w':
153 	case 'x':
154 	case 'y':
155 	case 'z':	goto yy32;
156 	case ':':	goto yy35;
157 	default:	goto yy4;
158 	}
159 yy7:
160 	++YYCURSOR;
161 	switch ((yych = *YYCURSOR)) {
162 	case '?':	goto yy29;
163 	default:	goto yy8;
164 	}
165 yy8:
166 #line 62 "ext/pdo/pdo_sql_parser.re"
167 	{ RET(PDO_PARSER_BIND_POS); }
168 #line 169 "ext/pdo/pdo_sql_parser.c"
169 yy9:
170 	++YYCURSOR;
171 	switch ((yych = *YYCURSOR)) {
172 	case '*':	goto yy19;
173 	default:	goto yy13;
174 	}
175 yy10:
176 #line 65 "ext/pdo/pdo_sql_parser.re"
177 	{ RET(PDO_PARSER_TEXT); }
178 #line 179 "ext/pdo/pdo_sql_parser.c"
179 yy11:
180 	yych = *++YYCURSOR;
181 	switch (yych) {
182 	case '-':	goto yy14;
183 	default:	goto yy13;
184 	}
185 yy12:
186 	++YYCURSOR;
187 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
188 	yych = *YYCURSOR;
189 yy13:
190 	switch (yych) {
191 	case 0x00:
192 	case '"':
193 	case '\'':
194 	case ':':
195 	case '?':	goto yy10;
196 	default:	goto yy12;
197 	}
198 yy14:
199 	++YYCURSOR;
200 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
201 	yych = *YYCURSOR;
202 	switch (yych) {
203 	case 0x00:
204 	case '"':
205 	case '\'':
206 	case ':':
207 	case '?':	goto yy17;
208 	case '\n':
209 	case '\r':	goto yy12;
210 	default:	goto yy14;
211 	}
212 yy16:
213 #line 64 "ext/pdo/pdo_sql_parser.re"
214 	{ RET(PDO_PARSER_TEXT); }
215 #line 216 "ext/pdo/pdo_sql_parser.c"
216 yy17:
217 	++YYCURSOR;
218 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
219 	yych = *YYCURSOR;
220 	switch (yych) {
221 	case '\n':
222 	case '\r':	goto yy16;
223 	default:	goto yy17;
224 	}
225 yy19:
226 	yyaccept = 1;
227 	YYMARKER = ++YYCURSOR;
228 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
229 	yych = *YYCURSOR;
230 	switch (yych) {
231 	case 0x00:
232 	case '"':
233 	case '\'':
234 	case ':':
235 	case '?':	goto yy21;
236 	case '*':	goto yy23;
237 	default:	goto yy19;
238 	}
239 yy21:
240 	++YYCURSOR;
241 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
242 	yych = *YYCURSOR;
243 	switch (yych) {
244 	case '*':	goto yy26;
245 	default:	goto yy21;
246 	}
247 yy23:
248 	yyaccept = 1;
249 	YYMARKER = ++YYCURSOR;
250 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
251 	yych = *YYCURSOR;
252 	switch (yych) {
253 	case 0x00:
254 	case '"':
255 	case '\'':
256 	case ':':
257 	case '?':	goto yy21;
258 	case '*':	goto yy23;
259 	case '/':	goto yy25;
260 	default:	goto yy19;
261 	}
262 yy25:
263 	yych = *++YYCURSOR;
264 	switch (yych) {
265 	case 0x00:
266 	case '"':
267 	case '\'':
268 	case ':':
269 	case '?':	goto yy16;
270 	default:	goto yy12;
271 	}
272 yy26:
273 	++YYCURSOR;
274 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
275 	yych = *YYCURSOR;
276 	switch (yych) {
277 	case '*':	goto yy26;
278 	case '/':	goto yy28;
279 	default:	goto yy21;
280 	}
281 yy28:
282 	yych = *++YYCURSOR;
283 	goto yy16;
284 yy29:
285 	++YYCURSOR;
286 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
287 	yych = *YYCURSOR;
288 	switch (yych) {
289 	case '?':	goto yy29;
290 	default:	goto yy31;
291 	}
292 yy31:
293 #line 60 "ext/pdo/pdo_sql_parser.re"
294 	{ RET(PDO_PARSER_TEXT); }
295 #line 296 "ext/pdo/pdo_sql_parser.c"
296 yy32:
297 	++YYCURSOR;
298 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
299 	yych = *YYCURSOR;
300 	switch (yych) {
301 	case '0':
302 	case '1':
303 	case '2':
304 	case '3':
305 	case '4':
306 	case '5':
307 	case '6':
308 	case '7':
309 	case '8':
310 	case '9':
311 	case 'A':
312 	case 'B':
313 	case 'C':
314 	case 'D':
315 	case 'E':
316 	case 'F':
317 	case 'G':
318 	case 'H':
319 	case 'I':
320 	case 'J':
321 	case 'K':
322 	case 'L':
323 	case 'M':
324 	case 'N':
325 	case 'O':
326 	case 'P':
327 	case 'Q':
328 	case 'R':
329 	case 'S':
330 	case 'T':
331 	case 'U':
332 	case 'V':
333 	case 'W':
334 	case 'X':
335 	case 'Y':
336 	case 'Z':
337 	case '_':
338 	case 'a':
339 	case 'b':
340 	case 'c':
341 	case 'd':
342 	case 'e':
343 	case 'f':
344 	case 'g':
345 	case 'h':
346 	case 'i':
347 	case 'j':
348 	case 'k':
349 	case 'l':
350 	case 'm':
351 	case 'n':
352 	case 'o':
353 	case 'p':
354 	case 'q':
355 	case 'r':
356 	case 's':
357 	case 't':
358 	case 'u':
359 	case 'v':
360 	case 'w':
361 	case 'x':
362 	case 'y':
363 	case 'z':	goto yy32;
364 	default:	goto yy34;
365 	}
366 yy34:
367 #line 61 "ext/pdo/pdo_sql_parser.re"
368 	{ RET(PDO_PARSER_BIND); }
369 #line 370 "ext/pdo/pdo_sql_parser.c"
370 yy35:
371 	++YYCURSOR;
372 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
373 	yych = *YYCURSOR;
374 	switch (yych) {
375 	case ':':	goto yy35;
376 	default:	goto yy31;
377 	}
378 yy37:
379 	++YYCURSOR;
380 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
381 	yych = *YYCURSOR;
382 yy38:
383 	switch (yych) {
384 	case 0x00:	goto yy2;
385 	case '\'':	goto yy40;
386 	case '\\':	goto yy39;
387 	default:	goto yy37;
388 	}
389 yy39:
390 	++YYCURSOR;
391 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
392 	yych = *YYCURSOR;
393 	if (yych <= 0x00) goto yy2;
394 	goto yy37;
395 yy40:
396 	++YYCURSOR;
397 #line 59 "ext/pdo/pdo_sql_parser.re"
398 	{ RET(PDO_PARSER_TEXT); }
399 #line 400 "ext/pdo/pdo_sql_parser.c"
400 yy42:
401 	++YYCURSOR;
402 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
403 	yych = *YYCURSOR;
404 yy43:
405 	switch (yych) {
406 	case 0x00:	goto yy2;
407 	case '"':	goto yy45;
408 	case '\\':	goto yy44;
409 	default:	goto yy42;
410 	}
411 yy44:
412 	++YYCURSOR;
413 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
414 	yych = *YYCURSOR;
415 	if (yych <= 0x00) goto yy2;
416 	goto yy42;
417 yy45:
418 	++YYCURSOR;
419 #line 58 "ext/pdo/pdo_sql_parser.re"
420 	{ RET(PDO_PARSER_TEXT); }
421 #line 422 "ext/pdo/pdo_sql_parser.c"
422 }
423 #line 66 "ext/pdo/pdo_sql_parser.re"
424 
425 }
426 
427 struct placeholder {
428 	char *pos;
429 	int len;
430 	int bindno;
431 	int qlen;		/* quoted length of value */
432 	char *quoted;	/* quoted value */
433 	int freeq;
434 	struct placeholder *next;
435 };
436 
pdo_parse_params(pdo_stmt_t * stmt,char * inquery,int inquery_len,char ** outquery,int * outquery_len TSRMLS_DC)437 PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
438 	char **outquery, int *outquery_len TSRMLS_DC)
439 {
440 	Scanner s;
441 	char *ptr, *newbuffer;
442 	int t;
443 	int bindno = 0;
444 	int ret = 0;
445 	int newbuffer_len;
446 	HashTable *params;
447 	struct pdo_bound_param_data *param;
448 	int query_type = PDO_PLACEHOLDER_NONE;
449 	struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
450 
451 	ptr = *outquery;
452 	s.cur = inquery;
453 	s.end = inquery + inquery_len + 1;
454 
455 	/* phase 1: look for args */
456 	while((t = scan(&s)) != PDO_PARSER_EOI) {
457 		if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
458 			if (t == PDO_PARSER_BIND) {
459 				int len = s.cur - s.tok;
460 				if ((inquery < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
461 					continue;
462 				}
463 				query_type |= PDO_PLACEHOLDER_NAMED;
464 			} else {
465 				query_type |= PDO_PLACEHOLDER_POSITIONAL;
466 			}
467 
468 			plc = emalloc(sizeof(*plc));
469 			memset(plc, 0, sizeof(*plc));
470 			plc->next = NULL;
471 			plc->pos = s.tok;
472 			plc->len = s.cur - s.tok;
473 			plc->bindno = bindno++;
474 
475 			if (placetail) {
476 				placetail->next = plc;
477 			} else {
478 				placeholders = plc;
479 			}
480 			placetail = plc;
481 		}
482 	}
483 
484 	if (bindno == 0) {
485 		/* nothing to do; good! */
486 		return 0;
487 	}
488 
489 	/* did the query make sense to me? */
490 	if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
491 		/* they mixed both types; punt */
492 		pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
493 		ret = -1;
494 		goto clean_up;
495 	}
496 
497 	if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
498 		/* query matches native syntax */
499 		ret = 0;
500 		goto clean_up;
501 	}
502 
503 	if (stmt->named_rewrite_template) {
504 		/* magic/hack.
505 		 * We we pretend that the query was positional even if
506 		 * it was named so that we fall into the
507 		 * named rewrite case below.  Not too pretty,
508 		 * but it works. */
509 		query_type = PDO_PLACEHOLDER_POSITIONAL;
510 	}
511 
512 	params = stmt->bound_params;
513 
514 	/* Do we have placeholders but no bound params */
515 	if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
516 		pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
517 		ret = -1;
518 		goto clean_up;
519 	}
520 
521 	if (params && bindno != zend_hash_num_elements(params) && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
522 		/* extra bit of validation for instances when same params are bound more then once */
523 		if (query_type != PDO_PLACEHOLDER_POSITIONAL && bindno > zend_hash_num_elements(params)) {
524 			int ok = 1;
525 			for (plc = placeholders; plc; plc = plc->next) {
526 				if (zend_hash_find(params, plc->pos, plc->len, (void**) &param) == FAILURE) {
527 					ok = 0;
528 					break;
529 				}
530 			}
531 			if (ok) {
532 				goto safe;
533 			}
534 		}
535 		pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "number of bound variables does not match number of tokens" TSRMLS_CC);
536 		ret = -1;
537 		goto clean_up;
538 	}
539 safe:
540 	/* what are we going to do ? */
541 	if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
542 		/* query generation */
543 
544 		newbuffer_len = inquery_len;
545 
546 		/* let's quote all the values */
547 		for (plc = placeholders; plc; plc = plc->next) {
548 			if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
549 				ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
550 			} else {
551 				ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
552 			}
553 			if (ret == FAILURE) {
554 				/* parameter was not defined */
555 				ret = -1;
556 				pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
557 				goto clean_up;
558 			}
559 			if (stmt->dbh->methods->quoter) {
560 				if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
561 					php_stream *stm;
562 
563 					php_stream_from_zval_no_verify(stm, &param->parameter);
564 					if (stm) {
565 						size_t len;
566 						char *buf = NULL;
567 
568 						len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
569 						if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
570 								param->param_type TSRMLS_CC)) {
571 							/* bork */
572 							ret = -1;
573 							strncpy(stmt->error_code, stmt->dbh->error_code, 6);
574 							if (buf) {
575 								efree(buf);
576 							}
577 							goto clean_up;
578 						}
579 						if (buf) {
580 							efree(buf);
581 						}
582 					} else {
583 						pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
584 						ret = -1;
585 						goto clean_up;
586 					}
587 					plc->freeq = 1;
588 				} else {
589 					zval tmp_param = *param->parameter;
590 					zval_copy_ctor(&tmp_param);
591 					switch (Z_TYPE(tmp_param)) {
592 						case IS_NULL:
593 							plc->quoted = "NULL";
594 							plc->qlen = sizeof("NULL")-1;
595 							plc->freeq = 0;
596 							break;
597 
598 						case IS_BOOL:
599 							convert_to_long(&tmp_param);
600 							/* fall through */
601 						case IS_LONG:
602 						case IS_DOUBLE:
603 							convert_to_string(&tmp_param);
604 							plc->qlen = Z_STRLEN(tmp_param);
605 							plc->quoted = estrdup(Z_STRVAL(tmp_param));
606 							plc->freeq = 1;
607 							break;
608 
609 						default:
610 							convert_to_string(&tmp_param);
611 							if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL(tmp_param),
612 									Z_STRLEN(tmp_param), &plc->quoted, &plc->qlen,
613 									param->param_type TSRMLS_CC)) {
614 								/* bork */
615 								ret = -1;
616 								strncpy(stmt->error_code, stmt->dbh->error_code, 6);
617 								goto clean_up;
618 							}
619 							plc->freeq = 1;
620 					}
621 					zval_dtor(&tmp_param);
622 				}
623 			} else {
624 				plc->quoted = Z_STRVAL_P(param->parameter);
625 				plc->qlen = Z_STRLEN_P(param->parameter);
626 			}
627 			newbuffer_len += plc->qlen;
628 		}
629 
630 rewrite:
631 		/* allocate output buffer */
632 		newbuffer = emalloc(newbuffer_len + 1);
633 		*outquery = newbuffer;
634 
635 		/* and build the query */
636 		plc = placeholders;
637 		ptr = inquery;
638 
639 		do {
640 			t = plc->pos - ptr;
641 			if (t) {
642 				memcpy(newbuffer, ptr, t);
643 				newbuffer += t;
644 			}
645 			memcpy(newbuffer, plc->quoted, plc->qlen);
646 			newbuffer += plc->qlen;
647 			ptr = plc->pos + plc->len;
648 
649 			plc = plc->next;
650 		} while (plc);
651 
652 		t = (inquery + inquery_len) - ptr;
653 		if (t) {
654 			memcpy(newbuffer, ptr, t);
655 			newbuffer += t;
656 		}
657 		*newbuffer = '\0';
658 		*outquery_len = newbuffer - *outquery;
659 
660 		ret = 1;
661 		goto clean_up;
662 
663 	} else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
664 		/* rewrite ? to :pdoX */
665 		char *name, *idxbuf;
666 		const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
667 		int bind_no = 1;
668 
669 		newbuffer_len = inquery_len;
670 
671 		if (stmt->bound_param_map == NULL) {
672 			ALLOC_HASHTABLE(stmt->bound_param_map);
673 			zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
674 		}
675 
676 		for (plc = placeholders; plc; plc = plc->next) {
677 			int skip_map = 0;
678 			char *p;
679 			name = estrndup(plc->pos, plc->len);
680 
681 			/* check if bound parameter is already available */
682 			if (!strcmp(name, "?") || zend_hash_find(stmt->bound_param_map, name, plc->len + 1, (void**) &p) == FAILURE) {
683 				spprintf(&idxbuf, 0, tmpl, bind_no++);
684 			} else {
685 				idxbuf = estrdup(p);
686 				skip_map = 1;
687 			}
688 
689 			plc->quoted = idxbuf;
690 			plc->qlen = strlen(plc->quoted);
691 			plc->freeq = 1;
692 			newbuffer_len += plc->qlen;
693 
694 			if (!skip_map && stmt->named_rewrite_template) {
695 				/* create a mapping */
696 				zend_hash_update(stmt->bound_param_map, name, plc->len + 1, idxbuf, plc->qlen + 1, NULL);
697 			}
698 
699 			/* map number to name */
700 			zend_hash_index_update(stmt->bound_param_map, plc->bindno, idxbuf, plc->qlen + 1, NULL);
701 
702 			efree(name);
703 		}
704 
705 		goto rewrite;
706 
707 	} else {
708 		/* rewrite :name to ? */
709 
710 		newbuffer_len = inquery_len;
711 
712 		if (stmt->bound_param_map == NULL) {
713 			ALLOC_HASHTABLE(stmt->bound_param_map);
714 			zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
715 		}
716 
717 		for (plc = placeholders; plc; plc = plc->next) {
718 			char *name;
719 
720 			name = estrndup(plc->pos, plc->len);
721 			zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
722 			efree(name);
723 			plc->quoted = "?";
724 			plc->qlen = 1;
725 		}
726 
727 		goto rewrite;
728 	}
729 
730 clean_up:
731 
732 	while (placeholders) {
733 		plc = placeholders;
734 		placeholders = plc->next;
735 
736 		if (plc->freeq) {
737 			efree(plc->quoted);
738 		}
739 
740 		efree(plc);
741 	}
742 
743 	return ret;
744 }
745 
746 #if 0
747 int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
748 		int *outquery_len TSRMLS_DC)
749 {
750 	Scanner s;
751 	char *ptr;
752 	int t;
753 	int bindno = 0;
754 	int newbuffer_len;
755 	int padding;
756 	HashTable *params = stmt->bound_params;
757 	struct pdo_bound_param_data *param;
758 	/* allocate buffer for query with expanded binds, ptr is our writing pointer */
759 	newbuffer_len = inquery_len;
760 
761 	/* calculate the possible padding factor due to quoting */
762 	if(stmt->dbh->max_escaped_char_length) {
763 		padding = stmt->dbh->max_escaped_char_length;
764 	} else {
765 		padding = 3;
766 	}
767 	if(params) {
768 		zend_hash_internal_pointer_reset(params);
769 		while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
770 			if(param->parameter) {
771 				convert_to_string(param->parameter);
772 				/* accommodate a string that needs to be fully quoted
773                    bind placeholders are at least 2 characters, so
774                    the accommodate their own "'s
775                 */
776 				newbuffer_len += padding * Z_STRLEN_P(param->parameter);
777 			}
778 			zend_hash_move_forward(params);
779 		}
780 	}
781 	*outquery = (char *) emalloc(newbuffer_len + 1);
782 	*outquery_len = 0;
783 
784 	ptr = *outquery;
785 	s.cur = inquery;
786 	while((t = scan(&s)) != PDO_PARSER_EOI) {
787 		if(t == PDO_PARSER_TEXT) {
788 			memcpy(ptr, s.tok, s.cur - s.tok);
789 			ptr += (s.cur - s.tok);
790 			*outquery_len += (s.cur - s.tok);
791 		}
792 		else if(t == PDO_PARSER_BIND) {
793 			if(!params) {
794 				/* error */
795 				efree(*outquery);
796 				*outquery = NULL;
797 				return (int) (s.cur - inquery);
798 			}
799 			/* lookup bind first via hash and then index */
800 			/* stupid keys need to be null-terminated, even though we know their length */
801 			if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))
802 			    ||
803 			   (SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)))
804 			{
805 				char *quotedstr;
806 				int quotedstrlen;
807 				/* restore the in-string key, doesn't need null-termination here */
808 				/* currently everything is a string here */
809 
810 				/* quote the bind value if necessary */
811 				if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
812 					Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
813 				{
814 					memcpy(ptr, quotedstr, quotedstrlen);
815 					ptr += quotedstrlen;
816 					*outquery_len += quotedstrlen;
817 					efree(quotedstr);
818 				} else {
819 					memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
820 					ptr += Z_STRLEN_P(param->parameter);
821 					*outquery_len += (Z_STRLEN_P(param->parameter));
822 				}
823 			}
824 			else {
825 				/* error and cleanup */
826 				efree(*outquery);
827 				*outquery = NULL;
828 				return (int) (s.cur - inquery);
829 			}
830 			bindno++;
831 		}
832 		else if(t == PDO_PARSER_BIND_POS) {
833 			if(!params) {
834 				/* error */
835 				efree(*outquery);
836 				*outquery = NULL;
837 				return (int) (s.cur - inquery);
838 			}
839 			/* lookup bind by index */
840 			if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))
841 			{
842 				char *quotedstr;
843 				int quotedstrlen;
844 				/* currently everything is a string here */
845 
846 				/* quote the bind value if necessary */
847 				if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
848 					Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
849 				{
850 					memcpy(ptr, quotedstr, quotedstrlen);
851 					ptr += quotedstrlen;
852 					*outquery_len += quotedstrlen;
853 					efree(quotedstr);
854 				} else {
855 					memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
856 					ptr += Z_STRLEN_P(param->parameter);
857 					*outquery_len += (Z_STRLEN_P(param->parameter));
858 				}
859 			}
860 			else {
861 				/* error and cleanup */
862 				efree(*outquery);
863 				*outquery = NULL;
864 				return (int) (s.cur - inquery);
865 			}
866 			bindno++;
867 		}
868 	}
869 	*ptr = '\0';
870 	return 0;
871 }
872 #endif
873 
874 /*
875  * Local variables:
876  * tab-width: 4
877  * c-basic-offset: 4
878  * End:
879  * vim600: noet sw=4 ts=4 fdm=marker ft=c
880  * vim<600: noet sw=4 ts=4
881  */
882