]> granicus.if.org Git - php/commitdiff
implement mapping of :name to ? parameters for drivers that only support ?
authorWez Furlong <wez@php.net>
Sun, 13 Feb 2005 06:29:35 +0000 (06:29 +0000)
committerWez Furlong <wez@php.net>
Sun, 13 Feb 2005 06:29:35 +0000 (06:29 +0000)
placeholders.
The current restriction is that you may not use the same named parameter
more than one in a given query, as there is a danger of scary things happen
with the zval if it gets bound multiple times.

ext/pdo/pdo_sql_parser.re
ext/pdo/pdo_stmt.c
ext/pdo/php_pdo_driver.h

index 68d678536295e16503d02bc78974e99d8dc181b6..97e7616f5df8d9d148d869d2c1cf6fe774bc8493 100644 (file)
@@ -259,10 +259,25 @@ 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;
+               }
 
-               /* HARD!.  We need to remember the mapping and bind those positions. */
-               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "cannot map :name to ? in this version" TSRMLS_CC);
-               ret = -1;
+               goto rewrite;
        }
 
 clean_up:
index 2b165acaf8b0f531373a983e5d3a05bc8053096b..b70eda3d240596d8c6ace34d90d0bdb40a5cb0fb 100755 (executable)
@@ -73,6 +73,37 @@ static PHP_FUNCTION(dbstmt_constructor) /* {{{ */
 }
 /* }}} */
 
+static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC)
+{
+       if (stmt->bound_param_map) {
+               /* rewriting :name to ? style.
+                * We need to fixup the parameter numbers on the parameters.
+                * If we find that a given named parameter has been used twice,
+                * we will raise an error, as we can't be sure that it is safe
+                * to bind multiple parameters onto the same zval in the underlying
+                * driver */
+               char **name;
+               int position = 0;
+               zend_hash_internal_pointer_reset(stmt->bound_param_map);
+               while (SUCCESS == zend_hash_get_current_data(stmt->bound_param_map, (void**)&name)) {
+                       if (strcmp(name, param->name)) {
+                               position++;
+                               zend_hash_move_forward(stmt->bound_param_map);
+                               continue;
+                       }
+                       if (param->paramno >= 0) {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO refuses to handle repeating the same :named parameter for multiple positions with this driver, as it might be unsafe to do so.  Consider using a separate name for each parameter instead" TSRMLS_CC);
+                               return -1;
+                       }
+                       param->paramno = position;
+                       return 1;
+               }
+               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
+               return 0;
+       }
+       return 1;       
+}
+
 /* trigger callback hook for parameters */
 static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC)
 {
@@ -83,14 +114,13 @@ static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_typ
        if (!stmt->methods->param_hook) {
                return 1;
        }
-       
+
        ht = stmt->bound_params;
 
 iterate:
        if (ht) {
                zend_hash_internal_pointer_reset(ht);
                while (SUCCESS == zend_hash_get_current_data(ht, (void**)&param)) {
-
                        if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
                                ret = 0;
                                break;
@@ -141,6 +171,7 @@ int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC)
                        }
                }
 
+#if 0
                /* update the column index on named bound parameters */
                if (stmt->bound_params) {
                        struct pdo_bound_param_data *param;
@@ -150,6 +181,7 @@ int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC)
                                param->paramno = col;
                        }
                }
+#endif
                if (stmt->bound_columns) {
                        struct pdo_bound_param_data *param;
 
@@ -253,6 +285,10 @@ static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_s
                zend_hash_index_update(hash, param->paramno, param, sizeof(*param), (void**)&pparam);
        }
 
+       if (!rewrite_name_to_position(stmt, pparam TSRMLS_CC)) {
+               return 0;
+       }
+       
        /* tell the driver we just created a parameter */
        if (stmt->methods->param_hook) {
                return stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC TSRMLS_CC);
@@ -1232,6 +1268,10 @@ static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
                zend_hash_destroy(stmt->bound_params);
                FREE_HASHTABLE(stmt->bound_params);
        }
+       if (stmt->bound_param_map) {
+               zend_hash_destroy(stmt->bound_param_map);
+               FREE_HASHTABLE(stmt->bound_param_map);
+       }
        if (stmt->bound_columns) {
                zend_hash_destroy(stmt->bound_columns);
                FREE_HASHTABLE(stmt->bound_columns);
index 465be2e518a455ca530c049359978cd0b13374dc..fea279afc7665a6f2e01f1f1557511cfb9fb5cab 100755 (executable)
@@ -35,7 +35,7 @@ struct pdo_bound_param_data;
 # define FALSE 0
 #endif
 
-#define PDO_DRIVER_API 20050206
+#define PDO_DRIVER_API 20050213
 
 enum pdo_param_type {
        PDO_PARAM_NULL,
@@ -502,6 +502,8 @@ struct _pdo_stmt_t {
        /* keep track of bound input parameters.  Some drivers support
         * input/output parameters, but you can't rely on that working */
        HashTable *bound_params;
+       /* When rewriting from named to positional, this maps positions to names */
+       HashTable *bound_param_map;
        /* keep track of PHP variables bound to named (or positional) columns
         * in the result set */
        HashTable *bound_columns;