From: George Schlossnagle Date: Tue, 18 May 2004 15:19:31 +0000 (+0000) Subject: handle binding/quoting of queries for drivers with emulated prepares X-Git-Tag: RELEASE_0_1~152 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a97e1a66466a6a59a6bf1d1ede4a2493822080fb;p=php handle binding/quoting of queries for drivers with emulated prepares --- diff --git a/ext/pdo/Makefile.frag b/ext/pdo/Makefile.frag index 5b8cf71f6e..1b34423608 100644 --- a/ext/pdo/Makefile.frag +++ b/ext/pdo/Makefile.frag @@ -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 > $@ diff --git a/ext/pdo/config.m4 b/ext/pdo/config.m4 index 29fb185a9f..1f62139bd6 100755 --- a/ext/pdo/config.m4 +++ b/ext/pdo/config.m4 @@ -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 diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 2529506390..c05a5f847e 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -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 index 0000000000..08ea83df23 --- /dev/null +++ b/ext/pdo/pdo_sql_parser.re @@ -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**)¶m)) { + 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 **)¶m)) + || + (SUCCESS == zend_hash_index_find(params, bindno, (void **)¶m))) + { + 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), "edstr, "edstrlen 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 + */ diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 21d40926fe..0ed46571dc 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -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), - "edstr, "edstrlen 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(¶m, 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; } /* }}} */ diff --git a/ext/pdo/php_pdo.h b/ext/pdo/php_pdo.h index a7fbd90894..cfa1f2b626 100755 --- a/ext/pdo/php_pdo.h +++ b/ext/pdo/php_pdo.h @@ -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 diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 96f6e914a6..ecaab98351 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -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 index 0000000000..8cc0558304 --- /dev/null +++ b/ext/pdo/php_pdo_sql_parser.h @@ -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