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