Annotation of embedaddon/php/ext/pdo/pdo_sql_parser.re, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 The PHP Group |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 3.01 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available through the world-wide-web at the following url: |
! 10: | http://www.php.net/license/3_01.txt |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Author: George Schlossnagle <george@omniti.com> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18:
! 19: /* $Id: pdo_sql_parser.re 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: #include "php.h"
! 22: #include "php_pdo_driver.h"
! 23: #include "php_pdo_int.h"
! 24:
! 25: #define PDO_PARSER_TEXT 1
! 26: #define PDO_PARSER_BIND 2
! 27: #define PDO_PARSER_BIND_POS 3
! 28: #define PDO_PARSER_EOI 4
! 29:
! 30: #define RET(i) {s->cur = cursor; return i; }
! 31: #define SKIP_ONE(i) {s->cur = s->tok + 1; return i; }
! 32:
! 33: #define YYCTYPE unsigned char
! 34: #define YYCURSOR cursor
! 35: #define YYLIMIT cursor
! 36: #define YYMARKER s->ptr
! 37: #define YYFILL(n)
! 38:
! 39: typedef struct Scanner {
! 40: char *ptr, *cur, *tok;
! 41: } Scanner;
! 42:
! 43: static int scan(Scanner *s)
! 44: {
! 45: char *cursor = s->cur;
! 46:
! 47: s->tok = cursor;
! 48: /*!re2c
! 49: BINDCHR = [:][a-zA-Z0-9_]+;
! 50: QUESTION = [?];
! 51: COMMENTS = ("/*"([^*]+|[*]+[^/*])*[*]*"*/"|"--"[^\r\n]*);
! 52: SPECIALS = [:?"'];
! 53: MULTICHAR = [:?];
! 54: EOF = [\000];
! 55: ANYNOEOF = [\001-\377];
! 56: */
! 57:
! 58: /*!re2c
! 59: (["](([\\]ANYNOEOF)|ANYNOEOF\["\\])*["]) { RET(PDO_PARSER_TEXT); }
! 60: (['](([\\]ANYNOEOF)|ANYNOEOF\['\\])*[']) { RET(PDO_PARSER_TEXT); }
! 61: MULTICHAR{2,} { RET(PDO_PARSER_TEXT); }
! 62: BINDCHR { RET(PDO_PARSER_BIND); }
! 63: QUESTION { RET(PDO_PARSER_BIND_POS); }
! 64: SPECIALS { SKIP_ONE(PDO_PARSER_TEXT); }
! 65: COMMENTS { RET(PDO_PARSER_TEXT); }
! 66: (ANYNOEOF\SPECIALS)+ { RET(PDO_PARSER_TEXT); }
! 67: EOF { RET(PDO_PARSER_EOI); }
! 68: */
! 69: }
! 70:
! 71: struct placeholder {
! 72: char *pos;
! 73: int len;
! 74: int bindno;
! 75: int qlen; /* quoted length of value */
! 76: char *quoted; /* quoted value */
! 77: int freeq;
! 78: struct placeholder *next;
! 79: };
! 80:
! 81: PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
! 82: char **outquery, int *outquery_len TSRMLS_DC)
! 83: {
! 84: Scanner s;
! 85: char *ptr, *newbuffer;
! 86: int t;
! 87: int bindno = 0;
! 88: int ret = 0;
! 89: int newbuffer_len;
! 90: HashTable *params;
! 91: struct pdo_bound_param_data *param;
! 92: int query_type = PDO_PLACEHOLDER_NONE;
! 93: struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
! 94:
! 95: ptr = *outquery;
! 96: s.cur = inquery;
! 97:
! 98: /* phase 1: look for args */
! 99: while((t = scan(&s)) != PDO_PARSER_EOI) {
! 100: if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
! 101: if (t == PDO_PARSER_BIND) {
! 102: int len = s.cur - s.tok;
! 103: if ((inquery < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
! 104: continue;
! 105: }
! 106: query_type |= PDO_PLACEHOLDER_NAMED;
! 107: } else {
! 108: query_type |= PDO_PLACEHOLDER_POSITIONAL;
! 109: }
! 110:
! 111: plc = emalloc(sizeof(*plc));
! 112: memset(plc, 0, sizeof(*plc));
! 113: plc->next = NULL;
! 114: plc->pos = s.tok;
! 115: plc->len = s.cur - s.tok;
! 116: plc->bindno = bindno++;
! 117:
! 118: if (placetail) {
! 119: placetail->next = plc;
! 120: } else {
! 121: placeholders = plc;
! 122: }
! 123: placetail = plc;
! 124: }
! 125: }
! 126:
! 127: if (bindno == 0) {
! 128: /* nothing to do; good! */
! 129: return 0;
! 130: }
! 131:
! 132: /* did the query make sense to me? */
! 133: if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
! 134: /* they mixed both types; punt */
! 135: pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
! 136: ret = -1;
! 137: goto clean_up;
! 138: }
! 139:
! 140: if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
! 141: /* query matches native syntax */
! 142: ret = 0;
! 143: goto clean_up;
! 144: }
! 145:
! 146: if (stmt->named_rewrite_template) {
! 147: /* magic/hack.
! 148: * We we pretend that the query was positional even if
! 149: * it was named so that we fall into the
! 150: * named rewrite case below. Not too pretty,
! 151: * but it works. */
! 152: query_type = PDO_PLACEHOLDER_POSITIONAL;
! 153: }
! 154:
! 155: params = stmt->bound_params;
! 156:
! 157: /* Do we have placeholders but no bound params */
! 158: if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
! 159: pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
! 160: ret = -1;
! 161: goto clean_up;
! 162: }
! 163:
! 164: if (params && bindno != zend_hash_num_elements(params) && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
! 165: /* extra bit of validation for instances when same params are bound more then once */
! 166: if (query_type != PDO_PLACEHOLDER_POSITIONAL && bindno > zend_hash_num_elements(params)) {
! 167: int ok = 1;
! 168: for (plc = placeholders; plc; plc = plc->next) {
! 169: if (zend_hash_find(params, plc->pos, plc->len, (void**) ¶m) == FAILURE) {
! 170: ok = 0;
! 171: break;
! 172: }
! 173: }
! 174: if (ok) {
! 175: goto safe;
! 176: }
! 177: }
! 178: pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "number of bound variables does not match number of tokens" TSRMLS_CC);
! 179: ret = -1;
! 180: goto clean_up;
! 181: }
! 182: safe:
! 183: /* what are we going to do ? */
! 184: if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
! 185: /* query generation */
! 186:
! 187: newbuffer_len = inquery_len;
! 188:
! 189: /* let's quote all the values */
! 190: for (plc = placeholders; plc; plc = plc->next) {
! 191: if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
! 192: ret = zend_hash_index_find(params, plc->bindno, (void**) ¶m);
! 193: } else {
! 194: ret = zend_hash_find(params, plc->pos, plc->len, (void**) ¶m);
! 195: }
! 196: if (ret == FAILURE) {
! 197: /* parameter was not defined */
! 198: ret = -1;
! 199: pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
! 200: goto clean_up;
! 201: }
! 202: if (stmt->dbh->methods->quoter) {
! 203: if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
! 204: php_stream *stm;
! 205:
! 206: php_stream_from_zval_no_verify(stm, ¶m->parameter);
! 207: if (stm) {
! 208: size_t len;
! 209: char *buf = NULL;
! 210:
! 211: len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
! 212: if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
! 213: param->param_type TSRMLS_CC)) {
! 214: /* bork */
! 215: ret = -1;
! 216: strncpy(stmt->error_code, stmt->dbh->error_code, 6);
! 217: if (buf) {
! 218: efree(buf);
! 219: }
! 220: goto clean_up;
! 221: }
! 222: if (buf) {
! 223: efree(buf);
! 224: }
! 225: } else {
! 226: pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
! 227: ret = -1;
! 228: goto clean_up;
! 229: }
! 230: plc->freeq = 1;
! 231: } else {
! 232: switch (Z_TYPE_P(param->parameter)) {
! 233: case IS_NULL:
! 234: plc->quoted = "NULL";
! 235: plc->qlen = sizeof("NULL")-1;
! 236: plc->freeq = 0;
! 237: break;
! 238:
! 239: case IS_BOOL:
! 240: convert_to_long(param->parameter);
! 241:
! 242: case IS_LONG:
! 243: case IS_DOUBLE:
! 244: convert_to_string(param->parameter);
! 245: plc->qlen = Z_STRLEN_P(param->parameter);
! 246: plc->quoted = Z_STRVAL_P(param->parameter);
! 247: plc->freeq = 0;
! 248: break;
! 249:
! 250: default:
! 251: convert_to_string(param->parameter);
! 252: if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
! 253: Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
! 254: param->param_type TSRMLS_CC)) {
! 255: /* bork */
! 256: ret = -1;
! 257: strncpy(stmt->error_code, stmt->dbh->error_code, 6);
! 258: goto clean_up;
! 259: }
! 260: plc->freeq = 1;
! 261: }
! 262: }
! 263: } else {
! 264: plc->quoted = Z_STRVAL_P(param->parameter);
! 265: plc->qlen = Z_STRLEN_P(param->parameter);
! 266: }
! 267: newbuffer_len += plc->qlen;
! 268: }
! 269:
! 270: rewrite:
! 271: /* allocate output buffer */
! 272: newbuffer = emalloc(newbuffer_len + 1);
! 273: *outquery = newbuffer;
! 274:
! 275: /* and build the query */
! 276: plc = placeholders;
! 277: ptr = inquery;
! 278:
! 279: do {
! 280: t = plc->pos - ptr;
! 281: if (t) {
! 282: memcpy(newbuffer, ptr, t);
! 283: newbuffer += t;
! 284: }
! 285: memcpy(newbuffer, plc->quoted, plc->qlen);
! 286: newbuffer += plc->qlen;
! 287: ptr = plc->pos + plc->len;
! 288:
! 289: plc = plc->next;
! 290: } while (plc);
! 291:
! 292: t = (inquery + inquery_len) - ptr;
! 293: if (t) {
! 294: memcpy(newbuffer, ptr, t);
! 295: newbuffer += t;
! 296: }
! 297: *newbuffer = '\0';
! 298: *outquery_len = newbuffer - *outquery;
! 299:
! 300: ret = 1;
! 301: goto clean_up;
! 302:
! 303: } else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
! 304: /* rewrite ? to :pdoX */
! 305: char *name, *idxbuf;
! 306: const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
! 307: int bind_no = 1;
! 308:
! 309: newbuffer_len = inquery_len;
! 310:
! 311: if (stmt->bound_param_map == NULL) {
! 312: ALLOC_HASHTABLE(stmt->bound_param_map);
! 313: zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
! 314: }
! 315:
! 316: for (plc = placeholders; plc; plc = plc->next) {
! 317: int skip_map = 0;
! 318: char *p;
! 319: name = estrndup(plc->pos, plc->len);
! 320:
! 321: /* check if bound parameter is already available */
! 322: if (!strcmp(name, "?") || zend_hash_find(stmt->bound_param_map, name, plc->len + 1, (void**) &p) == FAILURE) {
! 323: spprintf(&idxbuf, 0, tmpl, bind_no++);
! 324: } else {
! 325: idxbuf = estrdup(p);
! 326: skip_map = 1;
! 327: }
! 328:
! 329: plc->quoted = idxbuf;
! 330: plc->qlen = strlen(plc->quoted);
! 331: plc->freeq = 1;
! 332: newbuffer_len += plc->qlen;
! 333:
! 334: if (!skip_map && stmt->named_rewrite_template) {
! 335: /* create a mapping */
! 336: zend_hash_update(stmt->bound_param_map, name, plc->len + 1, idxbuf, plc->qlen + 1, NULL);
! 337: }
! 338:
! 339: /* map number to name */
! 340: zend_hash_index_update(stmt->bound_param_map, plc->bindno, idxbuf, plc->qlen + 1, NULL);
! 341:
! 342: efree(name);
! 343: }
! 344:
! 345: goto rewrite;
! 346:
! 347: } else {
! 348: /* rewrite :name to ? */
! 349:
! 350: newbuffer_len = inquery_len;
! 351:
! 352: if (stmt->bound_param_map == NULL) {
! 353: ALLOC_HASHTABLE(stmt->bound_param_map);
! 354: zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
! 355: }
! 356:
! 357: for (plc = placeholders; plc; plc = plc->next) {
! 358: char *name;
! 359:
! 360: name = estrndup(plc->pos, plc->len);
! 361: zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
! 362: efree(name);
! 363: plc->quoted = "?";
! 364: plc->qlen = 1;
! 365: }
! 366:
! 367: goto rewrite;
! 368: }
! 369:
! 370: clean_up:
! 371:
! 372: while (placeholders) {
! 373: plc = placeholders;
! 374: placeholders = plc->next;
! 375:
! 376: if (plc->freeq) {
! 377: efree(plc->quoted);
! 378: }
! 379:
! 380: efree(plc);
! 381: }
! 382:
! 383: return ret;
! 384: }
! 385:
! 386: #if 0
! 387: int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
! 388: int *outquery_len TSRMLS_DC)
! 389: {
! 390: Scanner s;
! 391: char *ptr;
! 392: int t;
! 393: int bindno = 0;
! 394: int newbuffer_len;
! 395: int padding;
! 396: HashTable *params = stmt->bound_params;
! 397: struct pdo_bound_param_data *param;
! 398: /* allocate buffer for query with expanded binds, ptr is our writing pointer */
! 399: newbuffer_len = inquery_len;
! 400:
! 401: /* calculate the possible padding factor due to quoting */
! 402: if(stmt->dbh->max_escaped_char_length) {
! 403: padding = stmt->dbh->max_escaped_char_length;
! 404: } else {
! 405: padding = 3;
! 406: }
! 407: if(params) {
! 408: zend_hash_internal_pointer_reset(params);
! 409: while (SUCCESS == zend_hash_get_current_data(params, (void**)¶m)) {
! 410: if(param->parameter) {
! 411: convert_to_string(param->parameter);
! 412: /* accomodate a string that needs to be fully quoted
! 413: bind placeholders are at least 2 characters, so
! 414: the accomodate their own "'s
! 415: */
! 416: newbuffer_len += padding * Z_STRLEN_P(param->parameter);
! 417: }
! 418: zend_hash_move_forward(params);
! 419: }
! 420: }
! 421: *outquery = (char *) emalloc(newbuffer_len + 1);
! 422: *outquery_len = 0;
! 423:
! 424: ptr = *outquery;
! 425: s.cur = inquery;
! 426: while((t = scan(&s)) != PDO_PARSER_EOI) {
! 427: if(t == PDO_PARSER_TEXT) {
! 428: memcpy(ptr, s.tok, s.cur - s.tok);
! 429: ptr += (s.cur - s.tok);
! 430: *outquery_len += (s.cur - s.tok);
! 431: }
! 432: else if(t == PDO_PARSER_BIND) {
! 433: if(!params) {
! 434: /* error */
! 435: efree(*outquery);
! 436: *outquery = NULL;
! 437: return (int) (s.cur - inquery);
! 438: }
! 439: /* lookup bind first via hash and then index */
! 440: /* stupid keys need to be null-terminated, even though we know their length */
! 441: if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)¶m))
! 442: ||
! 443: (SUCCESS == zend_hash_index_find(params, bindno, (void **)¶m)))
! 444: {
! 445: char *quotedstr;
! 446: int quotedstrlen;
! 447: /* restore the in-string key, doesn't need null-termination here */
! 448: /* currently everything is a string here */
! 449:
! 450: /* quote the bind value if necessary */
! 451: if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
! 452: Z_STRLEN_P(param->parameter), "edstr, "edstrlen TSRMLS_CC))
! 453: {
! 454: memcpy(ptr, quotedstr, quotedstrlen);
! 455: ptr += quotedstrlen;
! 456: *outquery_len += quotedstrlen;
! 457: efree(quotedstr);
! 458: } else {
! 459: memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
! 460: ptr += Z_STRLEN_P(param->parameter);
! 461: *outquery_len += (Z_STRLEN_P(param->parameter));
! 462: }
! 463: }
! 464: else {
! 465: /* error and cleanup */
! 466: efree(*outquery);
! 467: *outquery = NULL;
! 468: return (int) (s.cur - inquery);
! 469: }
! 470: bindno++;
! 471: }
! 472: else if(t == PDO_PARSER_BIND_POS) {
! 473: if(!params) {
! 474: /* error */
! 475: efree(*outquery);
! 476: *outquery = NULL;
! 477: return (int) (s.cur - inquery);
! 478: }
! 479: /* lookup bind by index */
! 480: if(SUCCESS == zend_hash_index_find(params, bindno, (void **)¶m))
! 481: {
! 482: char *quotedstr;
! 483: int quotedstrlen;
! 484: /* currently everything is a string here */
! 485:
! 486: /* quote the bind value if necessary */
! 487: if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
! 488: Z_STRLEN_P(param->parameter), "edstr, "edstrlen TSRMLS_CC))
! 489: {
! 490: memcpy(ptr, quotedstr, quotedstrlen);
! 491: ptr += quotedstrlen;
! 492: *outquery_len += quotedstrlen;
! 493: efree(quotedstr);
! 494: } else {
! 495: memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
! 496: ptr += Z_STRLEN_P(param->parameter);
! 497: *outquery_len += (Z_STRLEN_P(param->parameter));
! 498: }
! 499: }
! 500: else {
! 501: /* error and cleanup */
! 502: efree(*outquery);
! 503: *outquery = NULL;
! 504: return (int) (s.cur - inquery);
! 505: }
! 506: bindno++;
! 507: }
! 508: }
! 509: *ptr = '\0';
! 510: return 0;
! 511: }
! 512: #endif
! 513:
! 514: /*
! 515: * Local variables:
! 516: * tab-width: 4
! 517: * c-basic-offset: 4
! 518: * End:
! 519: * vim600: noet sw=4 ts=4 fdm=marker ft=c
! 520: * vim<600: noet sw=4 ts=4
! 521: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>