|
|
/*
+----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2004 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$ */
#include "php.h"#include "php_pdo_driver.h"#include "php_pdo_int.h"
#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 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_]+; QUESTION = [?]; SPECIALS = [:?"'];
ESCQQ = [\\]["];
ESCQ = [\\][']; EOF = [\000]; ANYNOEOF = [\001-\377]; */
/*!re2c
(["] (ESCQQ|ANYNOEOF\[\\"])* ["]) { RET(PDO_PARSER_TEXT); }
(['] (ESCQ|ANYNOEOF\[\\"])* [']) { RET(PDO_PARSER_TEXT); }
BINDCHR { RET(PDO_PARSER_BIND); } QUESTION { RET(PDO_PARSER_BIND_POS); } SPECIALS { RET(PDO_PARSER_TEXT); } (ANYNOEOF\SPECIALS)+ { RET(PDO_PARSER_TEXT); } EOF { RET(PDO_PARSER_EOI); } */ }
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; 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 */ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC); return -1; }
if (stmt->supports_placeholders == query_type) { /* query matches native syntax */ ret = 0; goto clean_up; }
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; } /* 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; 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, ¶m->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); efree(buf); goto clean_up; } 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_BOOL: convert_to_long(param->parameter); 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;
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 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 ? */ 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;}
#if 0int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery, int *outquery_len TSRMLS_DC){ Scanner s; char *ptr; int t; int bindno = 0; int newbuffer_len; int padding; 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;
/* calculate the possible padding factor due to quoting */ if(stmt->dbh->max_escaped_char_length) { padding = stmt->dbh->max_escaped_char_length; } else { padding = 3; } 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 += padding * 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)) != PDO_PARSER_EOI) { if(t == PDO_PARSER_TEXT) { memcpy(ptr, s.tok, s.cur - s.tok); ptr += (s.cur - s.tok); *outquery_len += (s.cur - s.tok); } else if(t == PDO_PARSER_BIND) { if(!params) { /* error */ efree(*outquery); *outquery = NULL; return (int) (s.cur - inquery); } /* lookup bind first via hash and then index */ /* stupid keys need to be null-terminated, even though we know their length */ if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)¶m)) || (SUCCESS == zend_hash_index_find(params, bindno, (void **)¶m))) { char *quotedstr; int quotedstrlen; /* restore the in-string key, doesn't need null-termination here */ /* currently everything is a string here */ /* 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)); } } else { /* error and cleanup */ efree(*outquery); *outquery = NULL; return (int) (s.cur - inquery); } bindno++; } else if(t == PDO_PARSER_BIND_POS) { if(!params) { /* error */ efree(*outquery); *outquery = NULL; return (int) (s.cur - inquery); } /* lookup bind by index */ if(SUCCESS == zend_hash_index_find(params, bindno, (void **)¶m)) { char *quotedstr; int quotedstrlen; /* currently everything is a string here */ /* 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)); } } else { /* error and cleanup */ efree(*outquery); *outquery = NULL; return (int) (s.cur - inquery); } bindno++; } } *ptr = '\0'; return 0;}#endif
/*
* Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker ft=c * vim<600: noet sw=4 ts=4 */
|