]> granicus.if.org Git - php/commitdiff
Revise query parser so that it can rewrite from one bind syntax to another.
authorWez Furlong <wez@php.net>
Fri, 21 Jan 2005 03:57:06 +0000 (03:57 +0000)
committerWez Furlong <wez@php.net>
Fri, 21 Jan 2005 03:57:06 +0000 (03:57 +0000)
Expose it as PDO_API.  No drivers utilize this feature yet.

ext/pdo/pdo_sql_parser.re
ext/pdo/pdo_stmt.c
ext/pdo/php_pdo_driver.h
ext/pdo/php_pdo_sql_parser.h [deleted file]

index 412f70ae060fcca45e3cc4cd905bb8c6740f0144..b779f168e8ae0e2e849b3c13652f192cde399409 100644 (file)
@@ -64,7 +64,192 @@ static int scan(Scanner *s)
        */      
 }
 
-int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery, 
+struct placeholder {
+       char *pos;
+       int len;
+       int bindno;
+       int qlen;               /* quoted length of value */
+       char *quoted;   /* quoted value */
+       int freeq;
+       struct placeholder *next;
+};
+
+PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, 
+       char **outquery, int *outquery_len TSRMLS_DC)
+{
+       Scanner s;
+       char *ptr, *newbuffer;
+       int t;
+       int bindno = 0;
+       int ret = 0;
+       int newbuffer_len;
+       int padding;
+       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;
+       s.lim = inquery + inquery_len;
+
+       /* 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) {
+                               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 */
+               strcpy(stmt->error_code, "HY093"); /* invalid parameter number */
+               return -1;
+       }
+
+       if (stmt->supports_placeholders == query_type) {
+               /* query matches native syntax */
+               ret = 0;
+               goto clean_up;
+       }
+
+       params = stmt->bound_params;
+       
+       /* 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;
+                               strcpy(stmt->error_code, "HY093"); /* invalid parameter number */
+                               goto clean_up;
+                       }
+                       if (stmt->dbh->methods->quoter) {
+                               if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+                                               Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen 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 idxbuf[32];
+               
+               newbuffer_len = inquery_len;
+
+               for (plc = placeholders; plc; plc = plc->next) {
+                       snprintf(idxbuf, sizeof(idxbuf), ":pdo%d", plc->bindno);
+                       plc->quoted = estrdup(idxbuf);
+                       plc->qlen = strlen(plc->quoted);
+                       plc->freeq = 1;
+                       newbuffer_len += plc->qlen;
+               }
+                               
+               goto rewrite;
+
+       } else {
+               /* rewrite :name to ? */
+
+               /* HARD!.  We need to remember the mapping and bind those positions. */
+               strcpy(stmt->error_code, "IM001"); /* Driver does not support this function */
+
+               ret = -1;
+       }
+
+clean_up:
+
+       while (placeholders) {
+               plc = placeholders;
+               placeholders = plc->next;
+
+               if (plc->freeq) {
+                       efree(plc->quoted);
+               }
+
+               efree(plc);
+       }
+
+       return ret;
+}
+
+#if 0
+int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery, 
                int *outquery_len TSRMLS_DC)
 {
        Scanner s;
@@ -190,6 +375,7 @@ int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **ou
        *ptr = '\0';
        return 0;
 }
+#endif
 
 /*
  * Local variables:
index 2e3aa6e25659f5bc26c1ea28b2daea279d200794..b0ae3f7301c0b486ee5fdc8bb845cae7e2629d09 100755 (executable)
@@ -32,7 +32,6 @@
 #include "php_pdo.h"
 #include "php_pdo_driver.h"
 #include "php_pdo_int.h"
-#include "php_pdo_sql_parser.h"
 #include "zend_exceptions.h"
 
 #if COMPILE_DL_PDO
@@ -311,17 +310,22 @@ static PHP_METHOD(PDOStatement, execute)
                }
        }
 
-       /* TODO: handle the non-native types too... doh. */
        if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
-               int error_pos;
                /* handle the emulated parameter binding,
          * stmt->active_query_string holds the query with binds expanded and 
                 * quoted.
          */
-               if((error_pos = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen, 
-                               &stmt->active_query_string, &stmt->active_query_stringlen)) != 0) {
-                       // parse error in handling the query
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error emulating placeholder binding in query at %.*s....", error_pos, stmt->query_string);
+
+               ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
+                       &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
+
+               if (ret == 0) {
+                       /* no changes were made */
+                       stmt->active_query_string = stmt->query_string;
+                       stmt->active_query_stringlen = stmt->active_query_stringlen;
+               } else if (ret == -1) {
+                       /* something broke */
+                       PDO_HANDLE_STMT_ERR();
                        RETURN_FALSE;
                }
        } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
@@ -329,10 +333,10 @@ static PHP_METHOD(PDOStatement, execute)
                RETURN_FALSE;
        }
        if (stmt->methods->executer(stmt TSRMLS_CC)) {
-               if (stmt->active_query_string) {
+               if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
                        efree(stmt->active_query_string);
-                       stmt->active_query_string = NULL;
                }
+               stmt->active_query_string = NULL;
                if (!stmt->executed) {
                        /* this is the first execute */
 
@@ -351,10 +355,10 @@ static PHP_METHOD(PDOStatement, execute)
                        
                RETURN_BOOL(ret);
        }
-       if (stmt->active_query_string) {
+       if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
                efree(stmt->active_query_string);
-               stmt->active_query_string = NULL;
        }
+       stmt->active_query_string = NULL;
        PDO_HANDLE_STMT_ERR();
        RETURN_FALSE;
 }
index 095bea32f3f88f3797fe5924720cad8e09952c26..1914567d7b9e077cf35a2ee16189a47d7f6f848a 100755 (executable)
@@ -534,6 +534,9 @@ PDO_API int php_pdo_parse_data_source(const char *data_source,
 
 PDO_API zend_class_entry *php_pdo_get_exception(void);
 
+PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, 
+       char **outquery, int *outquery_len TSRMLS_DC);
+
 #endif /* PHP_PDO_DRIVER_H */
 /*
  * Local variables:
diff --git a/ext/pdo/php_pdo_sql_parser.h b/ext/pdo/php_pdo_sql_parser.h
deleted file mode 100644 (file)
index 2c3850c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-  +----------------------------------------------------------------------+
-  | PHP Version 5                                                        |
-  +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2005 The PHP Group                                |
-  +----------------------------------------------------------------------+
-  | This source file is subject to version 3.0 of the PHP license,       |
-  | that is bundled with this package in the file LICENSE, and is        |
-  | available through the world-wide-web at the following url:           |
-  | http://www.php.net/license/3_0.txt.                                  |
-  | If you did not receive a copy of the PHP license and are unable to   |
-  | obtain it through the world-wide-web, please send a note to          |
-  | license@php.net so we can mail you a copy immediately.               |
-  +----------------------------------------------------------------------+
-  | Author: George Schlossnagle <george@omniti.com>                      |
-  +----------------------------------------------------------------------+
-*/
-
-/* $Id$ */
-
-#ifndef PHP_PDO_MYSQL_SQL_PARSER_H
-#define PHP_PDO_MYSQL_SQL_PARSER_H
-#include "php.h"
-int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
-                        int *outquery_len);
-
-#endif