Back to index

php5  5.3.10
pdo_sql_parser.c
Go to the documentation of this file.
00001 /* Generated by re2c 0.13.5 on Sat Jun  4 18:42:25 2011 */
00002 /*
00003   +----------------------------------------------------------------------+
00004   | PHP Version 5                                                        |
00005   +----------------------------------------------------------------------+
00006   | Copyright (c) 1997-2012 The PHP Group                                |
00007   +----------------------------------------------------------------------+
00008   | This source file is subject to version 3.01 of the PHP license,      |
00009   | that is bundled with this package in the file LICENSE, and is        |
00010   | available through the world-wide-web at the following url:           |
00011   | http://www.php.net/license/3_01.txt                                  |
00012   | If you did not receive a copy of the PHP license and are unable to   |
00013   | obtain it through the world-wide-web, please send a note to          |
00014   | license@php.net so we can mail you a copy immediately.               |
00015   +----------------------------------------------------------------------+
00016   | Author: George Schlossnagle <george@omniti.com>                      |
00017   +----------------------------------------------------------------------+
00018 */
00019 
00020 /* $Id: pdo_sql_parser.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php.h"
00023 #include "php_pdo_driver.h"
00024 #include "php_pdo_int.h"
00025 
00026 #define PDO_PARSER_TEXT 1
00027 #define PDO_PARSER_BIND 2
00028 #define PDO_PARSER_BIND_POS 3
00029 #define PDO_PARSER_EOI 4
00030 
00031 #define RET(i) {s->cur = cursor; return i; }
00032 #define SKIP_ONE(i) {s->cur = s->tok + 1; return i; }
00033 
00034 #define YYCTYPE         unsigned char
00035 #define YYCURSOR        cursor
00036 #define YYLIMIT         cursor
00037 #define YYMARKER        s->ptr
00038 #define YYFILL(n)
00039 
00040 typedef struct Scanner {
00041        char   *ptr, *cur, *tok;
00042 } Scanner;
00043 
00044 static int scan(Scanner *s) 
00045 {
00046        char *cursor = s->cur;
00047 
00048        s->tok = cursor;
00049 
00050 
00051        
00052 {
00053        YYCTYPE yych;
00054        unsigned int yyaccept = 0;
00055 
00056        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
00057        yych = *YYCURSOR;
00058        switch (yych) {
00059        case 0x00:    goto yy13;
00060        case '"':     goto yy2;
00061        case '\'':    goto yy4;
00062        case '-':     goto yy10;
00063        case '/':     goto yy8;
00064        case ':':     goto yy5;
00065        case '?':     goto yy6;
00066        default:      goto yy11;
00067        }
00068 yy2:
00069        yyaccept = 0;
00070        yych = *(YYMARKER = ++YYCURSOR);
00071        if (yych >= 0x01) goto yy43;
00072 yy3:
00073        { SKIP_ONE(PDO_PARSER_TEXT); }
00074 yy4:
00075        yyaccept = 0;
00076        yych = *(YYMARKER = ++YYCURSOR);
00077        if (yych <= 0x00) goto yy3;
00078        goto yy37;
00079 yy5:
00080        yych = *++YYCURSOR;
00081        switch (yych) {
00082        case '0':
00083        case '1':
00084        case '2':
00085        case '3':
00086        case '4':
00087        case '5':
00088        case '6':
00089        case '7':
00090        case '8':
00091        case '9':
00092        case 'A':
00093        case 'B':
00094        case 'C':
00095        case 'D':
00096        case 'E':
00097        case 'F':
00098        case 'G':
00099        case 'H':
00100        case 'I':
00101        case 'J':
00102        case 'K':
00103        case 'L':
00104        case 'M':
00105        case 'N':
00106        case 'O':
00107        case 'P':
00108        case 'Q':
00109        case 'R':
00110        case 'S':
00111        case 'T':
00112        case 'U':
00113        case 'V':
00114        case 'W':
00115        case 'X':
00116        case 'Y':
00117        case 'Z':
00118        case '_':
00119        case 'a':
00120        case 'b':
00121        case 'c':
00122        case 'd':
00123        case 'e':
00124        case 'f':
00125        case 'g':
00126        case 'h':
00127        case 'i':
00128        case 'j':
00129        case 'k':
00130        case 'l':
00131        case 'm':
00132        case 'n':
00133        case 'o':
00134        case 'p':
00135        case 'q':
00136        case 'r':
00137        case 's':
00138        case 't':
00139        case 'u':
00140        case 'v':
00141        case 'w':
00142        case 'x':
00143        case 'y':
00144        case 'z':     goto yy33;
00145        case ':':
00146        case '?':     goto yy30;
00147        default:      goto yy3;
00148        }
00149 yy6:
00150        ++YYCURSOR;
00151        switch ((yych = *YYCURSOR)) {
00152        case ':':
00153        case '?':     goto yy30;
00154        default:      goto yy7;
00155        }
00156 yy7:
00157        { RET(PDO_PARSER_BIND_POS); }
00158 yy8:
00159        ++YYCURSOR;
00160        switch ((yych = *YYCURSOR)) {
00161        case '*':     goto yy20;
00162        default:      goto yy12;
00163        }
00164 yy9:
00165        { RET(PDO_PARSER_TEXT); }
00166 yy10:
00167        yych = *++YYCURSOR;
00168        switch (yych) {
00169        case '-':     goto yy15;
00170        default:      goto yy12;
00171        }
00172 yy11:
00173        ++YYCURSOR;
00174        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00175        yych = *YYCURSOR;
00176 yy12:
00177        switch (yych) {
00178        case 0x00:
00179        case '"':
00180        case '\'':
00181        case ':':
00182        case '?':     goto yy9;
00183        default:      goto yy11;
00184        }
00185 yy13:
00186        ++YYCURSOR;
00187        { RET(PDO_PARSER_EOI); }
00188 yy15:
00189        ++YYCURSOR;
00190        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00191        yych = *YYCURSOR;
00192        switch (yych) {
00193        case 0x00:
00194        case '"':
00195        case '\'':
00196        case ':':
00197        case '?':     goto yy18;
00198        case '\n':
00199        case '\r':    goto yy11;
00200        default:      goto yy15;
00201        }
00202 yy17:
00203        { RET(PDO_PARSER_TEXT); }
00204 yy18:
00205        ++YYCURSOR;
00206        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00207        yych = *YYCURSOR;
00208        switch (yych) {
00209        case '\n':
00210        case '\r':    goto yy17;
00211        default:      goto yy18;
00212        }
00213 yy20:
00214        yyaccept = 1;
00215        YYMARKER = ++YYCURSOR;
00216        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00217        yych = *YYCURSOR;
00218        switch (yych) {
00219        case 0x00:
00220        case '"':
00221        case '\'':
00222        case ':':
00223        case '?':     goto yy22;
00224        case '*':     goto yy24;
00225        default:      goto yy20;
00226        }
00227 yy22:
00228        ++YYCURSOR;
00229        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00230        yych = *YYCURSOR;
00231        switch (yych) {
00232        case '*':     goto yy27;
00233        default:      goto yy22;
00234        }
00235 yy24:
00236        yyaccept = 1;
00237        YYMARKER = ++YYCURSOR;
00238        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
00239        yych = *YYCURSOR;
00240        switch (yych) {
00241        case 0x00:
00242        case '"':
00243        case '\'':
00244        case ':':
00245        case '?':     goto yy22;
00246        case '*':     goto yy24;
00247        case '/':     goto yy26;
00248        default:      goto yy20;
00249        }
00250 yy26:
00251        yych = *++YYCURSOR;
00252        switch (yych) {
00253        case 0x00:
00254        case '"':
00255        case '\'':
00256        case ':':
00257        case '?':     goto yy17;
00258        default:      goto yy11;
00259        }
00260 yy27:
00261        ++YYCURSOR;
00262        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00263        yych = *YYCURSOR;
00264        switch (yych) {
00265        case '*':     goto yy27;
00266        case '/':     goto yy29;
00267        default:      goto yy22;
00268        }
00269 yy29:
00270        yych = *++YYCURSOR;
00271        goto yy17;
00272 yy30:
00273        ++YYCURSOR;
00274        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00275        yych = *YYCURSOR;
00276        switch (yych) {
00277        case ':':
00278        case '?':     goto yy30;
00279        default:      goto yy32;
00280        }
00281 yy32:
00282        { RET(PDO_PARSER_TEXT); }
00283 yy33:
00284        ++YYCURSOR;
00285        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00286        yych = *YYCURSOR;
00287        switch (yych) {
00288        case '0':
00289        case '1':
00290        case '2':
00291        case '3':
00292        case '4':
00293        case '5':
00294        case '6':
00295        case '7':
00296        case '8':
00297        case '9':
00298        case 'A':
00299        case 'B':
00300        case 'C':
00301        case 'D':
00302        case 'E':
00303        case 'F':
00304        case 'G':
00305        case 'H':
00306        case 'I':
00307        case 'J':
00308        case 'K':
00309        case 'L':
00310        case 'M':
00311        case 'N':
00312        case 'O':
00313        case 'P':
00314        case 'Q':
00315        case 'R':
00316        case 'S':
00317        case 'T':
00318        case 'U':
00319        case 'V':
00320        case 'W':
00321        case 'X':
00322        case 'Y':
00323        case 'Z':
00324        case '_':
00325        case 'a':
00326        case 'b':
00327        case 'c':
00328        case 'd':
00329        case 'e':
00330        case 'f':
00331        case 'g':
00332        case 'h':
00333        case 'i':
00334        case 'j':
00335        case 'k':
00336        case 'l':
00337        case 'm':
00338        case 'n':
00339        case 'o':
00340        case 'p':
00341        case 'q':
00342        case 'r':
00343        case 's':
00344        case 't':
00345        case 'u':
00346        case 'v':
00347        case 'w':
00348        case 'x':
00349        case 'y':
00350        case 'z':     goto yy33;
00351        default:      goto yy35;
00352        }
00353 yy35:
00354        { RET(PDO_PARSER_BIND); }
00355 yy36:
00356        ++YYCURSOR;
00357        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00358        yych = *YYCURSOR;
00359 yy37:
00360        switch (yych) {
00361        case 0x00:    goto yy38;
00362        case '\'':    goto yy40;
00363        case '\\':    goto yy39;
00364        default:      goto yy36;
00365        }
00366 yy38:
00367        YYCURSOR = YYMARKER;
00368        switch (yyaccept) {
00369        case 0:       goto yy3;
00370        case 1:       goto yy9;
00371        }
00372 yy39:
00373        ++YYCURSOR;
00374        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00375        yych = *YYCURSOR;
00376        if (yych <= 0x00) goto yy38;
00377        goto yy36;
00378 yy40:
00379        ++YYCURSOR;
00380        { RET(PDO_PARSER_TEXT); }
00381 yy42:
00382        ++YYCURSOR;
00383        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00384        yych = *YYCURSOR;
00385 yy43:
00386        switch (yych) {
00387        case 0x00:    goto yy38;
00388        case '"':     goto yy45;
00389        case '\\':    goto yy44;
00390        default:      goto yy42;
00391        }
00392 yy44:
00393        ++YYCURSOR;
00394        if (YYLIMIT <= YYCURSOR) YYFILL(1);
00395        yych = *YYCURSOR;
00396        if (yych <= 0x00) goto yy38;
00397        goto yy42;
00398 yy45:
00399        ++YYCURSOR;
00400        { RET(PDO_PARSER_TEXT); }
00401 }
00402        
00403 }
00404 
00405 struct placeholder {
00406        char *pos;
00407        int len;
00408        int bindno;
00409        int qlen;            /* quoted length of value */
00410        char *quoted; /* quoted value */
00411        int freeq;
00412        struct placeholder *next;
00413 };
00414 
00415 PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, 
00416        char **outquery, int *outquery_len TSRMLS_DC)
00417 {
00418        Scanner s;
00419        char *ptr, *newbuffer;
00420        int t;
00421        int bindno = 0;
00422        int ret = 0;
00423        int newbuffer_len;
00424        HashTable *params;
00425        struct pdo_bound_param_data *param;
00426        int query_type = PDO_PLACEHOLDER_NONE;
00427        struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
00428 
00429        ptr = *outquery;
00430        s.cur = inquery;
00431 
00432        /* phase 1: look for args */
00433        while((t = scan(&s)) != PDO_PARSER_EOI) {
00434               if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
00435                      if (t == PDO_PARSER_BIND) {
00436                             int len = s.cur - s.tok;
00437                             if ((inquery < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
00438                                    continue;
00439                             }
00440                             query_type |= PDO_PLACEHOLDER_NAMED;
00441                      } else {
00442                             query_type |= PDO_PLACEHOLDER_POSITIONAL;
00443                      }
00444 
00445                      plc = emalloc(sizeof(*plc));
00446                      memset(plc, 0, sizeof(*plc));
00447                      plc->next = NULL;
00448                      plc->pos = s.tok;
00449                      plc->len = s.cur - s.tok;
00450                      plc->bindno = bindno++;
00451 
00452                      if (placetail) {
00453                             placetail->next = plc;
00454                      } else {
00455                             placeholders = plc;
00456                      }
00457                      placetail = plc;
00458               }
00459        }
00460 
00461        if (bindno == 0) {
00462               /* nothing to do; good! */
00463               return 0;
00464        }
00465 
00466        /* did the query make sense to me? */
00467        if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
00468               /* they mixed both types; punt */
00469               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
00470               ret = -1;
00471               goto clean_up;
00472        }
00473 
00474        if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
00475               /* query matches native syntax */
00476               ret = 0;
00477               goto clean_up;
00478        }
00479 
00480        if (stmt->named_rewrite_template) {
00481               /* magic/hack.
00482                * We we pretend that the query was positional even if
00483                * it was named so that we fall into the
00484                * named rewrite case below.  Not too pretty,
00485                * but it works. */
00486               query_type = PDO_PLACEHOLDER_POSITIONAL;
00487        }
00488        
00489        params = stmt->bound_params;
00490        
00491        /* Do we have placeholders but no bound params */
00492        if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
00493               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
00494               ret = -1;
00495               goto clean_up;
00496        }
00497 
00498        if (params && bindno != zend_hash_num_elements(params) && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
00499               /* extra bit of validation for instances when same params are bound more then once */
00500               if (query_type != PDO_PLACEHOLDER_POSITIONAL && bindno > zend_hash_num_elements(params)) {
00501                      int ok = 1;
00502                      for (plc = placeholders; plc; plc = plc->next) {
00503                             if (zend_hash_find(params, plc->pos, plc->len, (void**) &param) == FAILURE) {
00504                                    ok = 0;
00505                                    break;
00506                             }
00507                      }
00508                      if (ok) {
00509                             goto safe;
00510                      }
00511               }
00512               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "number of bound variables does not match number of tokens" TSRMLS_CC);
00513               ret = -1;
00514               goto clean_up;
00515        }
00516 safe:
00517        /* what are we going to do ? */
00518        if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
00519               /* query generation */
00520 
00521               newbuffer_len = inquery_len;
00522 
00523               /* let's quote all the values */   
00524               for (plc = placeholders; plc; plc = plc->next) {
00525                      if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
00526                             ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
00527                      } else {
00528                             ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
00529                      }
00530                      if (ret == FAILURE) {
00531                             /* parameter was not defined */
00532                             ret = -1;
00533                             pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
00534                             goto clean_up;
00535                      }
00536                      if (stmt->dbh->methods->quoter) {
00537                             if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
00538                                    php_stream *stm;
00539 
00540                                    php_stream_from_zval_no_verify(stm, &param->parameter);
00541                                    if (stm) {
00542                                           size_t len;
00543                                           char *buf = NULL;
00544                                    
00545                                           len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
00546                                           if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
00547                                                         param->param_type TSRMLS_CC)) {
00548                                                  /* bork */
00549                                                  ret = -1;
00550                                                  strcpy(stmt->error_code, stmt->dbh->error_code);
00551                                                  if (buf) {
00552                                                         efree(buf);
00553                                                  }
00554                                                  goto clean_up;
00555                                           }
00556                                           if (buf) {
00557                                                  efree(buf);
00558                                           }
00559                                    } else {
00560                                           pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
00561                                           ret = -1;
00562                                           goto clean_up;
00563                                    }
00564                                    plc->freeq = 1;
00565                             } else {
00566                                    switch (Z_TYPE_P(param->parameter)) {
00567                                           case IS_NULL:
00568                                                  plc->quoted = "NULL";
00569                                                  plc->qlen = sizeof("NULL")-1;
00570                                                  plc->freeq = 0;
00571                                                  break;
00572 
00573                                           case IS_LONG:
00574                                           case IS_DOUBLE:
00575                                                  convert_to_string(param->parameter);
00576                                                  plc->qlen = Z_STRLEN_P(param->parameter);
00577                                                  plc->quoted = Z_STRVAL_P(param->parameter);
00578                                                  plc->freeq = 0;
00579                                                  break;
00580 
00581                                           case IS_BOOL:
00582                                                  convert_to_long(param->parameter);
00583                                           default:
00584                                                  convert_to_string(param->parameter);
00585                                                  if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
00586                                                                Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
00587                                                                param->param_type TSRMLS_CC)) {
00588                                                         /* bork */
00589                                                         ret = -1;
00590                                                         strcpy(stmt->error_code, stmt->dbh->error_code);
00591                                                         goto clean_up;
00592                                                  }
00593                                                  plc->freeq = 1;
00594                                    }
00595                             }
00596                      } else {
00597                             plc->quoted = Z_STRVAL_P(param->parameter);
00598                             plc->qlen = Z_STRLEN_P(param->parameter);
00599                      }
00600                      newbuffer_len += plc->qlen;
00601               }
00602 
00603 rewrite:
00604               /* allocate output buffer */
00605               newbuffer = emalloc(newbuffer_len + 1);
00606               *outquery = newbuffer;
00607 
00608               /* and build the query */
00609               plc = placeholders;
00610               ptr = inquery;
00611 
00612               do {
00613                      t = plc->pos - ptr;
00614                      if (t) {
00615                             memcpy(newbuffer, ptr, t);
00616                             newbuffer += t;
00617                      }
00618                      memcpy(newbuffer, plc->quoted, plc->qlen);
00619                      newbuffer += plc->qlen;
00620                      ptr = plc->pos + plc->len;
00621 
00622                      plc = plc->next;
00623               } while (plc);
00624 
00625               t = (inquery + inquery_len) - ptr;
00626               if (t) {
00627                      memcpy(newbuffer, ptr, t);
00628                      newbuffer += t;
00629               }
00630               *newbuffer = '\0';
00631               *outquery_len = newbuffer - *outquery;
00632 
00633               ret = 1;
00634               goto clean_up;
00635 
00636        } else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
00637               /* rewrite ? to :pdoX */
00638               char *name, *idxbuf;
00639               const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
00640               int bind_no = 1;
00641               
00642               newbuffer_len = inquery_len;
00643 
00644               if (stmt->bound_param_map == NULL) {
00645                      ALLOC_HASHTABLE(stmt->bound_param_map);
00646                      zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
00647               }
00648 
00649               for (plc = placeholders; plc; plc = plc->next) {
00650                      int skip_map = 0;
00651                      char *p;
00652                      name = estrndup(plc->pos, plc->len);
00653 
00654                      /* check if bound parameter is already available */
00655                      if (!strcmp(name, "?") || zend_hash_find(stmt->bound_param_map, name, plc->len + 1, (void**) &p) == FAILURE) {
00656                             spprintf(&idxbuf, 0, tmpl, bind_no++);
00657                      } else {
00658                             idxbuf = estrdup(p);
00659                             skip_map = 1;
00660                      }
00661 
00662                      plc->quoted = idxbuf;
00663                      plc->qlen = strlen(plc->quoted);
00664                      plc->freeq = 1;
00665                      newbuffer_len += plc->qlen;
00666 
00667                      if (!skip_map && stmt->named_rewrite_template) {
00668                             /* create a mapping */
00669                             zend_hash_update(stmt->bound_param_map, name, plc->len + 1, idxbuf, plc->qlen + 1, NULL);
00670                      }
00671 
00672                      /* map number to name */
00673                      zend_hash_index_update(stmt->bound_param_map, plc->bindno, idxbuf, plc->qlen + 1, NULL);
00674                      
00675                      efree(name);
00676               }
00677                             
00678               goto rewrite;
00679 
00680        } else {
00681               /* rewrite :name to ? */
00682               
00683               newbuffer_len = inquery_len;
00684        
00685               if (stmt->bound_param_map == NULL) {
00686                      ALLOC_HASHTABLE(stmt->bound_param_map);
00687                      zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
00688               }
00689               
00690               for (plc = placeholders; plc; plc = plc->next) {
00691                      char *name;
00692                      
00693                      name = estrndup(plc->pos, plc->len);
00694                      zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
00695                      efree(name);
00696                      plc->quoted = "?";
00697                      plc->qlen = 1;
00698               }
00699 
00700               goto rewrite;
00701        }
00702 
00703 clean_up:
00704 
00705        while (placeholders) {
00706               plc = placeholders;
00707               placeholders = plc->next;
00708 
00709               if (plc->freeq) {
00710                      efree(plc->quoted);
00711               }
00712 
00713               efree(plc);
00714        }
00715 
00716        return ret;
00717 }
00718 
00719 #if 0
00720 int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery, 
00721               int *outquery_len TSRMLS_DC)
00722 {
00723        Scanner s;
00724        char *ptr;
00725        int t;
00726        int bindno = 0;
00727        int newbuffer_len;
00728        int padding;
00729        HashTable *params = stmt->bound_params;
00730        struct pdo_bound_param_data *param;
00731        /* allocate buffer for query with expanded binds, ptr is our writing pointer */
00732        newbuffer_len = inquery_len;
00733 
00734        /* calculate the possible padding factor due to quoting */
00735        if(stmt->dbh->max_escaped_char_length) {
00736               padding = stmt->dbh->max_escaped_char_length;
00737        } else {
00738               padding = 3;
00739        }
00740        if(params) {
00741               zend_hash_internal_pointer_reset(params);
00742               while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
00743                      if(param->parameter) {
00744                             convert_to_string(param->parameter);
00745                             /* accomodate a string that needs to be fully quoted
00746                    bind placeholders are at least 2 characters, so
00747                    the accomodate their own "'s
00748                 */
00749                             newbuffer_len += padding * Z_STRLEN_P(param->parameter);
00750                      }
00751                      zend_hash_move_forward(params);
00752               }
00753        }
00754        *outquery = (char *) emalloc(newbuffer_len + 1);
00755        *outquery_len = 0;
00756 
00757        ptr = *outquery;
00758        s.cur = inquery;
00759        while((t = scan(&s)) != PDO_PARSER_EOI) {
00760               if(t == PDO_PARSER_TEXT) {
00761                      memcpy(ptr, s.tok, s.cur - s.tok);
00762                      ptr += (s.cur - s.tok);
00763                      *outquery_len += (s.cur - s.tok);
00764               }
00765               else if(t == PDO_PARSER_BIND) {
00766                      if(!params) { 
00767                             /* error */
00768                             efree(*outquery);
00769                             *outquery = NULL;
00770                             return (int) (s.cur - inquery);
00771                      }
00772                      /* lookup bind first via hash and then index */
00773                      /* stupid keys need to be null-terminated, even though we know their length */
00774                      if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))  
00775                          ||
00776                         (SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))) 
00777                      {
00778                             char *quotedstr;
00779                             int quotedstrlen;
00780                             /* restore the in-string key, doesn't need null-termination here */
00781                             /* currently everything is a string here */
00782                             
00783                             /* quote the bind value if necessary */
00784                             if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter), 
00785                                    Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
00786                             {
00787                                    memcpy(ptr, quotedstr, quotedstrlen);
00788                                    ptr += quotedstrlen;
00789                                    *outquery_len += quotedstrlen;
00790                                    efree(quotedstr);
00791                             } else {
00792                                    memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
00793                                    ptr += Z_STRLEN_P(param->parameter);
00794                                    *outquery_len += (Z_STRLEN_P(param->parameter));
00795                             }
00796                      }
00797                      else {
00798                             /* error and cleanup */
00799                             efree(*outquery);
00800                             *outquery = NULL;
00801                             return (int) (s.cur - inquery);
00802                      }
00803                      bindno++;
00804               }
00805               else if(t == PDO_PARSER_BIND_POS) {
00806                      if(!params) { 
00807                             /* error */
00808                             efree(*outquery);
00809                             *outquery = NULL;
00810                             return (int) (s.cur - inquery);
00811                      }
00812                      /* lookup bind by index */
00813                      if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)) 
00814                      {
00815                             char *quotedstr;
00816                             int quotedstrlen;
00817                             /* currently everything is a string here */
00818                             
00819                             /* quote the bind value if necessary */
00820                             if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter), 
00821                                    Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
00822                             {
00823                                    memcpy(ptr, quotedstr, quotedstrlen);
00824                                    ptr += quotedstrlen;
00825                                    *outquery_len += quotedstrlen;
00826                                    efree(quotedstr);
00827                             } else {
00828                                    memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
00829                                    ptr += Z_STRLEN_P(param->parameter);
00830                                    *outquery_len += (Z_STRLEN_P(param->parameter));
00831                             }
00832                      }
00833                      else {
00834                             /* error and cleanup */
00835                             efree(*outquery);
00836                             *outquery = NULL;
00837                             return (int) (s.cur - inquery);
00838                      }
00839                      bindno++;
00840               }
00841        }      
00842        *ptr = '\0';
00843        return 0;
00844 }
00845 #endif
00846 
00847 /*
00848  * Local variables:
00849  * tab-width: 4
00850  * c-basic-offset: 4
00851  * End:
00852  * vim600: noet sw=4 ts=4 fdm=marker ft=c
00853  * vim<600: noet sw=4 ts=4
00854  */