]> granicus.if.org Git - php/commitdiff
Add PDO_FETCH_NAMED; closes PECL #4641 by providing a way to access columns
authorWez Furlong <wez@php.net>
Sun, 3 Jul 2005 03:49:44 +0000 (03:49 +0000)
committerWez Furlong <wez@php.net>
Sun, 3 Jul 2005 03:49:44 +0000 (03:49 +0000)
by name, even when multiple columns have the same name:

$sql = "SELECT 1 a, 2 a, 3 b, 4 c, 5 d, 6 c, 7 a";
echo "$sql\n";
print_r($db->query($sql)->fetchAll(PDO_FETCH_NAMED));

Array
(
    [0] => Array
        (
            [a] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 7
                )

            [b] => 3
            [c] => Array
                (
                    [0] => 4
                    [1] => 6
                )

            [d] => 5
        )
)

Also added two new attributes for use at prepare time;
PDO_ATTR_FETCH_TABLE_NAMES and PDO_ATTR_FETCH_CATALOG_NAMES instruct the driver
that the names of the columns that they return to PDO should include the table
and catalog names respectively.  Both attributes may be used together or
independently.  The catalog, table and column name components should be
separated by a . character.

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

index 7855cae9564a1828275335fd4b800e5c7e385079..210ed31603c55b652eff7c05683cde3cada1898d 100755 (executable)
@@ -318,6 +318,7 @@ PHP_MINIT_FUNCTION(pdo)
 #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
        REGISTER_LONG_CONSTANT("PDO_FETCH_SERIALIZE",(long)PDO_FETCH_SERIALIZE, CONST_CS|CONST_PERSISTENT);
 #endif
+       REGISTER_LONG_CONSTANT("PDO_FETCH_NAMED",(long)PDO_FETCH_NAMED, CONST_CS|CONST_PERSISTENT);
 
        REGISTER_LONG_CONSTANT("PDO_ATTR_AUTOCOMMIT",   (long)PDO_ATTR_AUTOCOMMIT,      CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("PDO_ATTR_PREFETCH",             (long)PDO_ATTR_PREFETCH,        CONST_CS|CONST_PERSISTENT);
@@ -333,6 +334,8 @@ PHP_MINIT_FUNCTION(pdo)
        REGISTER_LONG_CONSTANT("PDO_ATTR_ORACLE_NULLS", (long)PDO_ATTR_ORACLE_NULLS,    CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("PDO_ATTR_PERSISTENT",   (long)PDO_ATTR_PERSISTENT,              CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("PDO_ATTR_STATEMENT_CLASS",              (long)PDO_ATTR_STATEMENT_CLASS,                 CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("PDO_ATTR_FETCH_TABLE_NAMES",            (long)PDO_ATTR_FETCH_TABLE_NAMES,                       CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("PDO_ATTR_FETCH_CATALOG_NAMES",          (long)PDO_ATTR_FETCH_CATALOG_NAMES,                     CONST_CS|CONST_PERSISTENT);
        
        REGISTER_LONG_CONSTANT("PDO_ERRMODE_SILENT",    (long)PDO_ERRMODE_SILENT,               CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("PDO_ERRMODE_WARNING",   (long)PDO_ERRMODE_WARNING,              CONST_CS|CONST_PERSISTENT);
index 7c8be0605ebeb5954806abaa6840c8f73ce94b77..5166fbea3fef85463af0b03a3019d415e0d9ea49 100755 (executable)
@@ -735,6 +735,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                        case PDO_FETCH_ASSOC:
                        case PDO_FETCH_BOTH:
                        case PDO_FETCH_NUM:
+                       case PDO_FETCH_NAMED:
                                array_init(return_value);
                                break;
 
@@ -842,6 +843,43 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                        add_next_index_zval(return_value, val);
                                        break;
 
+                               case PDO_FETCH_NAMED:
+                                       /* already have an item with this name? */
+                                       {
+                                               zval **curr_val = NULL;
+                                               if (zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name,
+                                                                       strlen(stmt->columns[i].name)+1,
+                                                                       (void**)&curr_val) == SUCCESS) {
+                                                       zval *arr;
+                                                       if (Z_TYPE_PP(curr_val) != IS_ARRAY) {
+                                                               /* a little bit of black magic here:
+                                                                * we're creating a new array and swapping it for the
+                                                                * zval that's already stored in the hash under the name
+                                                                * we want.  We then add that zval to the array.
+                                                                * This is effectively the same thing as:
+                                                                * if (!is_array($hash[$name])) {
+                                                                *   $hash[$name] = array($hash[$name]);
+                                                                * }
+                                                                * */
+                                                               zval *cur;
+
+                                                               MAKE_STD_ZVAL(arr);
+                                                               array_init(arr);
+
+                                                               cur = *curr_val;
+                                                               *curr_val = arr;
+
+                                                               add_next_index_zval(arr, cur);
+                                                       } else {
+                                                               arr = *curr_val;
+                                                       }
+                                                       add_next_index_zval(arr, val);
+                                               } else {
+                                                       add_assoc_zval(return_value, stmt->columns[i].name, val);
+                                               }
+                                       }
+                                       break;
+
                                case PDO_FETCH_NUM:
                                        add_next_index_zval(return_value, val);
                                        break;
index 4d86cdeb598d1a65cd62c5a8695876aadb8f0b91..53cf2bcc8f24fa49b1496deb7170b0bd264c92f3 100755 (executable)
@@ -44,7 +44,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC);
 # define FALSE 0
 #endif
 
-#define PDO_DRIVER_API 20050610
+#define PDO_DRIVER_API 20050702
 
 enum pdo_param_type {
        PDO_PARAM_NULL,
@@ -89,6 +89,7 @@ enum pdo_fetch_type {
        PDO_FETCH_CLASS,        /* create an instance of named class, call ctor and set properties */
        PDO_FETCH_INTO,         /* fetch row into an existing object */
        PDO_FETCH_FUNC,         /* fetch into function and return its result */
+       PDO_FETCH_NAMED,    /* like PDO_FETCH_ASSOC, but can handle duplicate names */
        PDO_FETCH__MAX /* must be last */
 };
 
@@ -123,6 +124,8 @@ enum pdo_attribute_type {
        PDO_ATTR_ORACLE_NULLS,          /* convert empty strings to NULL */
        PDO_ATTR_PERSISTENT,            /* pconnect style connection */
        PDO_ATTR_STATEMENT_CLASS,       /* array(classname, array(ctor_args)) to specify the class of the constructed statement */
+       PDO_ATTR_FETCH_TABLE_NAMES, /* include table names in the column names, where available */
+       PDO_ATTR_FETCH_CATALOG_NAMES, /* include the catalog/db name names in the column names, where available */
 
        /* this defines the start of the range for driver specific options.
         * Drivers should define their own attribute constants beginning with this
@@ -156,24 +159,6 @@ typedef char pdo_error_type[6]; /* SQLSTATE */
 
 
 #define PDO_ERR_NONE                           "00000"
-#if 0
-/* generic error code values.
- * Don't want to go overboard with these.
- * */
-#define        PDO_ERR_SYNTAX                          "42000"         
-#define        PDO_ERR_CONSTRAINT                      "23000"
-#define        PDO_ERR_NOT_FOUND                       ""
-#define        PDO_ERR_ALREADY_EXISTS,
-#define        PDO_ERR_NOT_IMPLEMENTED,
-#define        PDO_ERR_MISMATCH,
-#define        PDO_ERR_TRUNCATED,
-#define        PDO_ERR_DISCONNECTED,
-#define        PDO_ERR_NO_PERM,
-
-       PDO_ERR_CANT_MAP                /* no way to map native error to the generic
-                                                        * codes; consult the native error for more info */
-};
-#endif
 
 enum pdo_error_mode {
        PDO_ERRMODE_SILENT,             /* just set error codes */