Back to index

php5  5.3.10
Classes | Defines | Typedefs | Functions
pdo_sql_parser.c File Reference
#include "php.h"
#include "php_pdo_driver.h"
#include "php_pdo_int.h"

Go to the source code of this file.

Classes

struct  Scanner
struct  placeholder

Defines

#define PDO_PARSER_TEXT   1
#define PDO_PARSER_BIND   2
#define PDO_PARSER_BIND_POS   3
#define PDO_PARSER_EOI   4
#define RET(i)   {s->cur = cursor; return i; }
#define SKIP_ONE(i)   {s->cur = s->tok + 1; return i; }
#define YYCTYPE   unsigned char
#define YYCURSOR   cursor
#define YYLIMIT   cursor
#define YYMARKER   s->ptr
#define YYFILL(n)

Typedefs

typedef struct Scanner Scanner

Functions

static int scan (Scanner *s)
PDO_API int pdo_parse_params (pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery, int *outquery_len TSRMLS_DC)

Class Documentation

struct Scanner

Definition at line 150 of file parse_date.c.

Collaboration diagram for Scanner:
Class Members
struct timelib_time * begin
char * cur
uchar * cur
struct timelib_time * end
struct timelib_error_container * errors
int fd
int have_begin_date
int have_date
int have_end_date
int have_period
int have_recurrences
unsigned int len
uchar * lim
unsigned int line
struct timelib_rel_time * period
uchar * pos
char * ptr
uchar * ptr
int recurrences
uchar * str
struct timelib_time * time
char * tok
uchar * tok
const timelib_tzdb * tzdb
struct placeholder

Definition at line 405 of file pdo_sql_parser.c.

Collaboration diagram for placeholder:
Class Members
int bindno
int freeq
int len
struct placeholder * next
char * pos
int qlen
char * quoted

Define Documentation

#define PDO_PARSER_BIND   2

Definition at line 27 of file pdo_sql_parser.c.

#define PDO_PARSER_BIND_POS   3

Definition at line 28 of file pdo_sql_parser.c.

#define PDO_PARSER_EOI   4

Definition at line 29 of file pdo_sql_parser.c.

#define PDO_PARSER_TEXT   1

Definition at line 26 of file pdo_sql_parser.c.

#define RET (   i)    {s->cur = cursor; return i; }

Definition at line 31 of file pdo_sql_parser.c.

#define SKIP_ONE (   i)    {s->cur = s->tok + 1; return i; }

Definition at line 32 of file pdo_sql_parser.c.

#define YYCTYPE   unsigned char

Definition at line 34 of file pdo_sql_parser.c.

#define YYCURSOR   cursor

Definition at line 35 of file pdo_sql_parser.c.

#define YYFILL (   n)

Definition at line 38 of file pdo_sql_parser.c.

#define YYLIMIT   cursor

Definition at line 36 of file pdo_sql_parser.c.

#define YYMARKER   s->ptr

Definition at line 37 of file pdo_sql_parser.c.


Typedef Documentation

typedef struct Scanner Scanner

Function Documentation

PDO_API int pdo_parse_params ( pdo_stmt_t *  stmt,
char *  inquery,
int  inquery_len,
char **  outquery,
int *outquery_len  TSRMLS_DC 
)

Definition at line 415 of file pdo_sql_parser.c.

{
       Scanner s;
       char *ptr, *newbuffer;
       int t;
       int bindno = 0;
       int ret = 0;
       int newbuffer_len;
       HashTable *params;
       struct pdo_bound_param_data *param;
       int query_type = PDO_PLACEHOLDER_NONE;
       struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;

       ptr = *outquery;
       s.cur = inquery;

       /* phase 1: look for args */
       while((t = scan(&s)) != PDO_PARSER_EOI) {
              if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
                     if (t == PDO_PARSER_BIND) {
                            int len = s.cur - s.tok;
                            if ((inquery < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
                                   continue;
                            }
                            query_type |= PDO_PLACEHOLDER_NAMED;
                     } else {
                            query_type |= PDO_PLACEHOLDER_POSITIONAL;
                     }

                     plc = emalloc(sizeof(*plc));
                     memset(plc, 0, sizeof(*plc));
                     plc->next = NULL;
                     plc->pos = s.tok;
                     plc->len = s.cur - s.tok;
                     plc->bindno = bindno++;

                     if (placetail) {
                            placetail->next = plc;
                     } else {
                            placeholders = plc;
                     }
                     placetail = plc;
              }
       }

       if (bindno == 0) {
              /* nothing to do; good! */
              return 0;
       }

       /* did the query make sense to me? */
       if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
              /* they mixed both types; punt */
              pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
              ret = -1;
              goto clean_up;
       }

       if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
              /* query matches native syntax */
              ret = 0;
              goto clean_up;
       }

       if (stmt->named_rewrite_template) {
              /* magic/hack.
               * We we pretend that the query was positional even if
               * it was named so that we fall into the
               * named rewrite case below.  Not too pretty,
               * but it works. */
              query_type = PDO_PLACEHOLDER_POSITIONAL;
       }
       
       params = stmt->bound_params;
       
       /* Do we have placeholders but no bound params */
       if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
              pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
              ret = -1;
              goto clean_up;
       }

       if (params && bindno != zend_hash_num_elements(params) && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
              /* extra bit of validation for instances when same params are bound more then once */
              if (query_type != PDO_PLACEHOLDER_POSITIONAL && bindno > zend_hash_num_elements(params)) {
                     int ok = 1;
                     for (plc = placeholders; plc; plc = plc->next) {
                            if (zend_hash_find(params, plc->pos, plc->len, (void**) &param) == FAILURE) {
                                   ok = 0;
                                   break;
                            }
                     }
                     if (ok) {
                            goto safe;
                     }
              }
              pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "number of bound variables does not match number of tokens" TSRMLS_CC);
              ret = -1;
              goto clean_up;
       }
safe:
       /* what are we going to do ? */
       if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
              /* query generation */

              newbuffer_len = inquery_len;

              /* let's quote all the values */   
              for (plc = placeholders; plc; plc = plc->next) {
                     if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
                            ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
                     } else {
                            ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
                     }
                     if (ret == FAILURE) {
                            /* parameter was not defined */
                            ret = -1;
                            pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
                            goto clean_up;
                     }
                     if (stmt->dbh->methods->quoter) {
                            if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
                                   php_stream *stm;

                                   php_stream_from_zval_no_verify(stm, &param->parameter);
                                   if (stm) {
                                          size_t len;
                                          char *buf = NULL;
                                   
                                          len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
                                          if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
                                                        param->param_type TSRMLS_CC)) {
                                                 /* bork */
                                                 ret = -1;
                                                 strcpy(stmt->error_code, stmt->dbh->error_code);
                                                 if (buf) {
                                                        efree(buf);
                                                 }
                                                 goto clean_up;
                                          }
                                          if (buf) {
                                                 efree(buf);
                                          }
                                   } else {
                                          pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
                                          ret = -1;
                                          goto clean_up;
                                   }
                                   plc->freeq = 1;
                            } else {
                                   switch (Z_TYPE_P(param->parameter)) {
                                          case IS_NULL:
                                                 plc->quoted = "NULL";
                                                 plc->qlen = sizeof("NULL")-1;
                                                 plc->freeq = 0;
                                                 break;

                                          case IS_LONG:
                                          case IS_DOUBLE:
                                                 convert_to_string(param->parameter);
                                                 plc->qlen = Z_STRLEN_P(param->parameter);
                                                 plc->quoted = Z_STRVAL_P(param->parameter);
                                                 plc->freeq = 0;
                                                 break;

                                          case IS_BOOL:
                                                 convert_to_long(param->parameter);
                                          default:
                                                 convert_to_string(param->parameter);
                                                 if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
                                                               Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
                                                               param->param_type TSRMLS_CC)) {
                                                        /* bork */
                                                        ret = -1;
                                                        strcpy(stmt->error_code, stmt->dbh->error_code);
                                                        goto clean_up;
                                                 }
                                                 plc->freeq = 1;
                                   }
                            }
                     } else {
                            plc->quoted = Z_STRVAL_P(param->parameter);
                            plc->qlen = Z_STRLEN_P(param->parameter);
                     }
                     newbuffer_len += plc->qlen;
              }

rewrite:
              /* allocate output buffer */
              newbuffer = emalloc(newbuffer_len + 1);
              *outquery = newbuffer;

              /* and build the query */
              plc = placeholders;
              ptr = inquery;

              do {
                     t = plc->pos - ptr;
                     if (t) {
                            memcpy(newbuffer, ptr, t);
                            newbuffer += t;
                     }
                     memcpy(newbuffer, plc->quoted, plc->qlen);
                     newbuffer += plc->qlen;
                     ptr = plc->pos + plc->len;

                     plc = plc->next;
              } while (plc);

              t = (inquery + inquery_len) - ptr;
              if (t) {
                     memcpy(newbuffer, ptr, t);
                     newbuffer += t;
              }
              *newbuffer = '\0';
              *outquery_len = newbuffer - *outquery;

              ret = 1;
              goto clean_up;

       } else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
              /* rewrite ? to :pdoX */
              char *name, *idxbuf;
              const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
              int bind_no = 1;
              
              newbuffer_len = inquery_len;

              if (stmt->bound_param_map == NULL) {
                     ALLOC_HASHTABLE(stmt->bound_param_map);
                     zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
              }

              for (plc = placeholders; plc; plc = plc->next) {
                     int skip_map = 0;
                     char *p;
                     name = estrndup(plc->pos, plc->len);

                     /* check if bound parameter is already available */
                     if (!strcmp(name, "?") || zend_hash_find(stmt->bound_param_map, name, plc->len + 1, (void**) &p) == FAILURE) {
                            spprintf(&idxbuf, 0, tmpl, bind_no++);
                     } else {
                            idxbuf = estrdup(p);
                            skip_map = 1;
                     }

                     plc->quoted = idxbuf;
                     plc->qlen = strlen(plc->quoted);
                     plc->freeq = 1;
                     newbuffer_len += plc->qlen;

                     if (!skip_map && stmt->named_rewrite_template) {
                            /* create a mapping */
                            zend_hash_update(stmt->bound_param_map, name, plc->len + 1, idxbuf, plc->qlen + 1, NULL);
                     }

                     /* map number to name */
                     zend_hash_index_update(stmt->bound_param_map, plc->bindno, idxbuf, plc->qlen + 1, NULL);
                     
                     efree(name);
              }
                            
              goto rewrite;

       } else {
              /* rewrite :name to ? */
              
              newbuffer_len = inquery_len;
       
              if (stmt->bound_param_map == NULL) {
                     ALLOC_HASHTABLE(stmt->bound_param_map);
                     zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
              }
              
              for (plc = placeholders; plc; plc = plc->next) {
                     char *name;
                     
                     name = estrndup(plc->pos, plc->len);
                     zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
                     efree(name);
                     plc->quoted = "?";
                     plc->qlen = 1;
              }

              goto rewrite;
       }

clean_up:

       while (placeholders) {
              plc = placeholders;
              placeholders = plc->next;

              if (plc->freeq) {
                     efree(plc->quoted);
              }

              efree(plc);
       }

       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int scan ( Scanner s) [static]

Definition at line 44 of file pdo_sql_parser.c.

{
       char *cursor = s->cur;

       s->tok = cursor;


       
{
       YYCTYPE yych;
       unsigned int yyaccept = 0;

       if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
       yych = *YYCURSOR;
       switch (yych) {
       case 0x00:    goto yy13;
       case '"':     goto yy2;
       case '\'':    goto yy4;
       case '-':     goto yy10;
       case '/':     goto yy8;
       case ':':     goto yy5;
       case '?':     goto yy6;
       default:      goto yy11;
       }
yy2:
       yyaccept = 0;
       yych = *(YYMARKER = ++YYCURSOR);
       if (yych >= 0x01) goto yy43;
yy3:
       { SKIP_ONE(PDO_PARSER_TEXT); }
yy4:
       yyaccept = 0;
       yych = *(YYMARKER = ++YYCURSOR);
       if (yych <= 0x00) goto yy3;
       goto yy37;
yy5:
       yych = *++YYCURSOR;
       switch (yych) {
       case '0':
       case '1':
       case '2':
       case '3':
       case '4':
       case '5':
       case '6':
       case '7':
       case '8':
       case '9':
       case 'A':
       case 'B':
       case 'C':
       case 'D':
       case 'E':
       case 'F':
       case 'G':
       case 'H':
       case 'I':
       case 'J':
       case 'K':
       case 'L':
       case 'M':
       case 'N':
       case 'O':
       case 'P':
       case 'Q':
       case 'R':
       case 'S':
       case 'T':
       case 'U':
       case 'V':
       case 'W':
       case 'X':
       case 'Y':
       case 'Z':
       case '_':
       case 'a':
       case 'b':
       case 'c':
       case 'd':
       case 'e':
       case 'f':
       case 'g':
       case 'h':
       case 'i':
       case 'j':
       case 'k':
       case 'l':
       case 'm':
       case 'n':
       case 'o':
       case 'p':
       case 'q':
       case 'r':
       case 's':
       case 't':
       case 'u':
       case 'v':
       case 'w':
       case 'x':
       case 'y':
       case 'z':     goto yy33;
       case ':':
       case '?':     goto yy30;
       default:      goto yy3;
       }
yy6:
       ++YYCURSOR;
       switch ((yych = *YYCURSOR)) {
       case ':':
       case '?':     goto yy30;
       default:      goto yy7;
       }
yy7:
       { RET(PDO_PARSER_BIND_POS); }
yy8:
       ++YYCURSOR;
       switch ((yych = *YYCURSOR)) {
       case '*':     goto yy20;
       default:      goto yy12;
       }
yy9:
       { RET(PDO_PARSER_TEXT); }
yy10:
       yych = *++YYCURSOR;
       switch (yych) {
       case '-':     goto yy15;
       default:      goto yy12;
       }
yy11:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
yy12:
       switch (yych) {
       case 0x00:
       case '"':
       case '\'':
       case ':':
       case '?':     goto yy9;
       default:      goto yy11;
       }
yy13:
       ++YYCURSOR;
       { RET(PDO_PARSER_EOI); }
yy15:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case 0x00:
       case '"':
       case '\'':
       case ':':
       case '?':     goto yy18;
       case '\n':
       case '\r':    goto yy11;
       default:      goto yy15;
       }
yy17:
       { RET(PDO_PARSER_TEXT); }
yy18:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case '\n':
       case '\r':    goto yy17;
       default:      goto yy18;
       }
yy20:
       yyaccept = 1;
       YYMARKER = ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case 0x00:
       case '"':
       case '\'':
       case ':':
       case '?':     goto yy22;
       case '*':     goto yy24;
       default:      goto yy20;
       }
yy22:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case '*':     goto yy27;
       default:      goto yy22;
       }
yy24:
       yyaccept = 1;
       YYMARKER = ++YYCURSOR;
       if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
       yych = *YYCURSOR;
       switch (yych) {
       case 0x00:
       case '"':
       case '\'':
       case ':':
       case '?':     goto yy22;
       case '*':     goto yy24;
       case '/':     goto yy26;
       default:      goto yy20;
       }
yy26:
       yych = *++YYCURSOR;
       switch (yych) {
       case 0x00:
       case '"':
       case '\'':
       case ':':
       case '?':     goto yy17;
       default:      goto yy11;
       }
yy27:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case '*':     goto yy27;
       case '/':     goto yy29;
       default:      goto yy22;
       }
yy29:
       yych = *++YYCURSOR;
       goto yy17;
yy30:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case ':':
       case '?':     goto yy30;
       default:      goto yy32;
       }
yy32:
       { RET(PDO_PARSER_TEXT); }
yy33:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       switch (yych) {
       case '0':
       case '1':
       case '2':
       case '3':
       case '4':
       case '5':
       case '6':
       case '7':
       case '8':
       case '9':
       case 'A':
       case 'B':
       case 'C':
       case 'D':
       case 'E':
       case 'F':
       case 'G':
       case 'H':
       case 'I':
       case 'J':
       case 'K':
       case 'L':
       case 'M':
       case 'N':
       case 'O':
       case 'P':
       case 'Q':
       case 'R':
       case 'S':
       case 'T':
       case 'U':
       case 'V':
       case 'W':
       case 'X':
       case 'Y':
       case 'Z':
       case '_':
       case 'a':
       case 'b':
       case 'c':
       case 'd':
       case 'e':
       case 'f':
       case 'g':
       case 'h':
       case 'i':
       case 'j':
       case 'k':
       case 'l':
       case 'm':
       case 'n':
       case 'o':
       case 'p':
       case 'q':
       case 'r':
       case 's':
       case 't':
       case 'u':
       case 'v':
       case 'w':
       case 'x':
       case 'y':
       case 'z':     goto yy33;
       default:      goto yy35;
       }
yy35:
       { RET(PDO_PARSER_BIND); }
yy36:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
yy37:
       switch (yych) {
       case 0x00:    goto yy38;
       case '\'':    goto yy40;
       case '\\':    goto yy39;
       default:      goto yy36;
       }
yy38:
       YYCURSOR = YYMARKER;
       switch (yyaccept) {
       case 0:       goto yy3;
       case 1:       goto yy9;
       }
yy39:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       if (yych <= 0x00) goto yy38;
       goto yy36;
yy40:
       ++YYCURSOR;
       { RET(PDO_PARSER_TEXT); }
yy42:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
yy43:
       switch (yych) {
       case 0x00:    goto yy38;
       case '"':     goto yy45;
       case '\\':    goto yy44;
       default:      goto yy42;
       }
yy44:
       ++YYCURSOR;
       if (YYLIMIT <= YYCURSOR) YYFILL(1);
       yych = *YYCURSOR;
       if (yych <= 0x00) goto yy38;
       goto yy42;
yy45:
       ++YYCURSOR;
       { RET(PDO_PARSER_TEXT); }
}
       
}

Here is the caller graph for this function: