From: Wez Furlong Date: Sun, 3 Jul 2005 03:49:44 +0000 (+0000) Subject: Add PDO_FETCH_NAMED; closes PECL #4641 by providing a way to access columns X-Git-Tag: php-5.1.0b3~213 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d4a158260b77e6d7590bfbd63b32b812f4851026;p=php Add PDO_FETCH_NAMED; closes PECL #4641 by providing a way to access columns 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. --- diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c index 7855cae956..210ed31603 100755 --- a/ext/pdo/pdo.c +++ b/ext/pdo/pdo.c @@ -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); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 7c8be0605e..5166fbea3f 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -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; diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 4d86cdeb59..53cf2bcc8f 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -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 */