From 6ddbfa073385d856a563b3229b5242d02e6e82af Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Fri, 21 Jan 2005 03:57:06 +0000 Subject: [PATCH] Revise query parser so that it can rewrite from one bind syntax to another. Expose it as PDO_API. No drivers utilize this feature yet. --- ext/pdo/pdo_sql_parser.re | 188 ++++++++++++++++++++++++++++++++++- ext/pdo/pdo_stmt.c | 26 +++-- ext/pdo/php_pdo_driver.h | 3 + ext/pdo/php_pdo_sql_parser.h | 27 ----- 4 files changed, 205 insertions(+), 39 deletions(-) delete mode 100644 ext/pdo/php_pdo_sql_parser.h diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re index 412f70ae06..b779f168e8 100644 --- a/ext/pdo/pdo_sql_parser.re +++ b/ext/pdo/pdo_sql_parser.re @@ -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**) ¶m); + } else { + ret = zend_hash_find(params, plc->pos, plc->len, (void**) ¶m); + } + 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: diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 2e3aa6e256..b0ae3f7301 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -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; } diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 095bea32f3..1914567d7b 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -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 index 2c3850c009..0000000000 --- a/ext/pdo/php_pdo_sql_parser.h +++ /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 | - +----------------------------------------------------------------------+ -*/ - -/* $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 -- 2.50.1