]> granicus.if.org Git - php/commitdiff
handle binding/quoting of queries for drivers with emulated prepares
authorGeorge Schlossnagle <gschlossnagle@php.net>
Tue, 18 May 2004 15:19:31 +0000 (15:19 +0000)
committerGeorge Schlossnagle <gschlossnagle@php.net>
Tue, 18 May 2004 15:19:31 +0000 (15:19 +0000)
ext/pdo/Makefile.frag
ext/pdo/config.m4
ext/pdo/pdo_dbh.c
ext/pdo/pdo_sql_parser.re [new file with mode: 0644]
ext/pdo/pdo_stmt.c
ext/pdo/php_pdo.h
ext/pdo/php_pdo_driver.h
ext/pdo/php_pdo_sql_parser.h [new file with mode: 0644]

index 5b8cf71f6e0486e2ac6073182489314d6ba8b886..1b344236085705378f40307b3866e0be994af526 100644 (file)
@@ -20,4 +20,8 @@ install-pdo-headers:
 # mini hack
 install: $(all_targets) $(install_targets) install-pdo-headers
 
+$(top_srcdir)/ext/pdo/pdo_sql_parser.c: $(top_srcdir)/ext/pdo/pdo_sql_parser.re
+       re2c -b $(top_srcdir)/ext/pdo/pdo_sql_parser.re > $@
 
+$(srcdir)/pdo_sql_parser.c: $(srcdir)/pdo_sql_parser.re
+       re2c -b $(srcdir)/pdo_sql_parser.re > $@
index 29fb185a9f7c4df8e70a0071141a2dfec082003a..1f62139bd6103126aefdbe28765fe9552852f634 100755 (executable)
@@ -5,6 +5,6 @@ PHP_ARG_ENABLE(pdo, whether to enable PDO support,
 [  --enable-pdo           Enable PHP Data Objects support])
 
 if test "$PHP_PDO" != "no"; then
-  PHP_NEW_EXTENSION(pdo, pdo.c pdo_dbh.c pdo_stmt.c, $ext_shared)
+  PHP_NEW_EXTENSION(pdo, pdo.c pdo_dbh.c pdo_stmt.c pdo_sql_parser.c, $ext_shared)
   PHP_ADD_MAKEFILE_FRAGMENT
 fi
index 2529506390bb5ec3609613d08648ec183ceb4bf6..c05a5f847eb50ce20f3931419e9145832fb7ee42 100755 (executable)
@@ -133,7 +133,9 @@ static PHP_METHOD(PDO, prepare)
        }
        
        stmt = ecalloc(1, sizeof(*stmt));
-       
+       /* uncoditionally keep this for later reference */
+       stmt->query_string = estrndup(statement, statement_len);
+       stmt->query_stringlen = statement_len;
        if (dbh->methods->preparer(dbh, statement, statement_len, stmt TSRMLS_CC)) {
                /* prepared; create a statement object for PHP land to access it */
                Z_TYPE_P(return_value) = IS_OBJECT;
@@ -146,9 +148,7 @@ static PHP_METHOD(PDO, prepare)
                stmt->dbh = dbh;
                return;
        }
-
        efree(stmt);
-
        RETURN_FALSE;
 }
 
diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re
new file mode 100644 (file)
index 0000000..08ea83d
--- /dev/null
@@ -0,0 +1,138 @@
+#include "php.h"
+#include "php_pdo_driver.h"
+
+#define TEXT 1
+#define BIND 2
+#define EOI 3
+
+#define RET(i) {s->cur = cursor; return i; }
+
+#define YYCTYPE         char
+#define YYCURSOR        cursor
+#define YYLIMIT         s->lim
+#define YYMARKER        s->ptr
+#define YYFILL(n)
+
+typedef struct Scanner {
+       char    *lim, *ptr, *cur, *tok;
+} Scanner;
+
+static int scan(Scanner *s) 
+{
+       char *cursor = s->cur;
+       std:
+               s->tok = cursor;
+       /*!re2c
+       BINDCHR         = [:][a-zA-Z0-9]+;
+       SPECIALS        = [:"];
+       ESC             = [\\]["];
+       EOF                     = [\000];
+       ANYNOEOF        = [\001-\377];
+       */
+
+       /*!re2c
+               (["] (ESC|ANYNOEOF\[\\"])* ["])         { RET(TEXT); }
+               BINDCHR { RET(BIND); }
+               SPECIALS        { RET(TEXT); }
+               (ANYNOEOF\SPECIALS)+ { RET(TEXT); }
+               EOF             { RET(EOI); }
+       */      
+}
+
+int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery, 
+                        int *outquery_len)
+{
+       Scanner s;
+       char *ptr;
+       int t;
+       int bindno = 0;
+       int newbuffer_len;
+       HashTable *params = stmt->bound_params;
+       struct pdo_bound_param_data *param;
+
+       /* allocate buffer for query with expanded binds, ptr is our writing pointer */
+       newbuffer_len = inquery_len;
+       if(params) {
+               zend_hash_internal_pointer_reset(params);
+               while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
+                       if(param->parameter) {
+                               convert_to_string(param->parameter);
+                               /* accomodate a string that needs to be fully quoted
+                   bind placeholders are at least 2 characters, so
+                   the accomodate their own "'s
+                */
+                               newbuffer_len += 2 * Z_STRLEN_P(param->parameter);
+                       }
+                       zend_hash_move_forward(params);
+               }
+       }
+       *outquery = (char *) emalloc(newbuffer_len + 1);
+       *outquery_len = 0;
+
+       ptr = *outquery;
+       s.cur = inquery;
+       s.lim = inquery + inquery_len;
+       while((t = scan(&s)) != EOI) {
+               if(t == TEXT) {
+                       memcpy(ptr, s.tok, s.cur - s.tok);
+                       ptr += (s.cur - s.tok);
+                       *outquery_len += (s.cur - s.tok);
+               }
+               else if(t == BIND) {
+                       if(!params) { 
+                               /* error */
+                               efree(*outquery);
+                               return 0;
+                       }
+                       /* lookup bind first via hash and then index */
+                       if((SUCCESS == zend_hash_find(params, s.tok+1, s.cur-s.tok,(void **)&param))  
+                           ||
+                          (SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))) 
+                       {
+                               char *quotedstr;
+                               int quotedstrlen;
+                               /* currently everything is a string here */
+                               
+                               /* add leading quote */
+                               *ptr = '"';
+                               ptr++;
+                               (*outquery_len)++;
+
+                               /* quote the bind value if necessary */
+                               if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter), 
+                                       Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
+                               {
+                                       memcpy(ptr, quotedstr, quotedstrlen);
+                                       ptr += quotedstrlen;
+                                       *outquery_len += quotedstrlen;
+                                       efree(quotedstr);
+                               } else {
+                                       memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
+                                       ptr += Z_STRLEN_P(param->parameter);
+                                       *outquery_len += (Z_STRLEN_P(param->parameter));
+                               }
+                               /* add trailing quote */
+                               *ptr = '"';
+                               ptr++;
+                               (*outquery_len)++;
+                       }
+                       else {
+                               /* error and cleanup */
+                               efree(*outquery);
+                               return 0;
+                       }
+                       bindno++;
+               }       
+       }       
+       *ptr = '\0';
+       return 1;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
index 21d40926fea465efe290325cc46009a93b33aff3..0ed46571dc3fe63edb11f7e670bb0eb675b27d0c 100755 (executable)
@@ -32,6 +32,7 @@
 #include "php_pdo.h"
 #include "php_pdo_driver.h"
 #include "php_pdo_int.h"
+#include "php_pdo_sql_parser.h"
 #include "zend_exceptions.h"
 
 /* {{{ content from zend_arg_defs.c:
@@ -228,6 +229,8 @@ static PHP_METHOD(PDOStatement, execute)
        pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC);
        zval *input_params = NULL;
        int ret = 1;
+       char *original_query;
+       int orginal_querylen;
 
        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
                RETURN_FALSE;
@@ -265,15 +268,6 @@ static PHP_METHOD(PDOStatement, execute)
                        }
 
                        param.param_type = PDO_PARAM_STR;
-#if 0
-                       if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 
-                          &quotedstr, &quotedstrlen TSRMLS_DC)) {
-                               int refcount = (*tmp)->refcount;
-                               zval_dtor(*tmp);
-                               ZVAL_STRINGL(*tmp, quotedstr, quotedstrlen, 0);
-                               (*tmp)->refcount = refcount;
-                       }
-#endif
                        param.parameter = *tmp;
 
                        if (!really_register_bound_param(&param, stmt, 1 TSRMLS_CC)) {
@@ -285,19 +279,21 @@ static PHP_METHOD(PDOStatement, execute)
        }
 
        if (stmt->dbh->emulate_prepare) {
-               /* XXX: here we need to:
-                *  - walk stmt->bound_params, quoting each zval value
-                *    (without modifying the zval)
-                *  - substitute these values according to name/position
-                *  - stash that into stmt->query_string
-                *
-                *  When the executer() is called, it will use that query string */
-
+               /* handle the emulated parameter binding,
+         * stmt->active_query_string holds the query with binds expanded and 
+                * quoted.
+         */
+               if(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
+                       RETURN_FALSE;
+               }
        } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
                RETURN_FALSE;
        }
-       
        if (stmt->methods->executer(stmt TSRMLS_CC)) {
+               efree(stmt->active_query_string);
+               stmt->active_query_string = NULL;
                if (!stmt->executed) {
                        /* this is the first execute */
 
@@ -316,6 +312,8 @@ static PHP_METHOD(PDOStatement, execute)
                        
                RETURN_BOOL(ret);
        }
+       efree(stmt->active_query_string);
+       stmt->active_query_string = NULL;
        RETURN_FALSE;
 }
 /* }}} */
index a7fbd90894f5141f1fafafed2ef2b95672936d9b..cfa1f2b626b11bbe085bfe5cad110feac4e0758a 100755 (executable)
@@ -20,6 +20,7 @@
 
 #ifndef PHP_PDO_H
 #define PHP_PDO_H
+#include "php.h"
 
 extern zend_module_entry pdo_module_entry;
 #define phpext_pdo_ptr &pdo_module_entry
index 96f6e914a68ce8c4907dcde14c6774825062687a..ecaab983516401ee8c5e5c1ec0c0d513bc4647b3 100755 (executable)
@@ -279,8 +279,13 @@ struct _pdo_stmt_t {
        /* not always meaningful */
        long row_count;
 
-       /* used only when PDO is emulating prepare for the driver */
+       /* used to hold the statement's current query */
        char *query_string;
+       int query_stringlen;
+
+       /* the copy of the query with expanded binds ONLY for emulated-prepare drivers */
+       char *active_query_string;
+       int active_query_stringlen;
 };
 
 /* call this in MINIT to register your PDO driver */
diff --git a/ext/pdo/php_pdo_sql_parser.h b/ext/pdo/php_pdo_sql_parser.h
new file mode 100644 (file)
index 0000000..8cc0558
--- /dev/null
@@ -0,0 +1,7 @@
+#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