Hi! As per my rfd from 2007-11-14, I prepared a FETCH_2D (work title) patch - where a row result consists of a two-dimensional hash, the first dimension being the table name, the second the field name.
Summary: I propose to rearrange FETCH mode constants, such that FETCH_NUM, FETCH_ASSOC and (new) FETCH_2D are bitwise combineable: FETCH_ASSOC | FETCH_NUM = FETCH_BOTH FETCH_2D | FETCH_NUM = FETCH_2D_NUM FETCH_2D is the "core" of my proposal. It's like the ATTR_FETCH_TABLE_NAMES, enhanced in arrays. Columns are to be found on the second level: $result[tablename][columname] Columns that don't result from a table are added to a "null base" (work title). The default "null base" is the first level array: $result[computedcolumn] The connection attribute ATTR_2D_NULLBASE (work title) defines an alternative "null base": $result[nullbase][computedcolumn] FETCH_2D should be combineable with FETCH_ASSOC and/or FETCH_NUM. The corresponding entries are added to the "null base" (a reference). Status: The attached patch against CVS PHP_5_3 supports the described functionality with pdo_mysql and pdo_firebird (my primary). Please let me know if I'm on a totally wrong path. HPO
diff -u -r1.18.2.1.2.5.2.7 firebird_statement.c --- ext/pdo_firebird/firebird_statement.c 16 Nov 2007 12:27:49 -0000 1.18.2.1.2.5.2.7 +++ ext/pdo_firebird/firebird_statement.c 19 Nov 2007 19:46:52 -0000 @@ -99,10 +99,7 @@ S->cursor_open = 0; /* assume all params have been bound */ - if ((S->statement_type == isc_info_sql_stmt_exec_procedure && - isc_dsql_execute2(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION, - S->in_sqlda, &S->out_sqlda)) - || isc_dsql_execute(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION, + if (isc_dsql_execute(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION, S->in_sqlda)) { break; } @@ -113,8 +110,8 @@ } *S->name = 0; - S->cursor_open = 1; - S->exhausted = 0; + S->cursor_open = (S->out_sqlda.sqln > 0); + S->exhausted = !S->cursor_open; return 1; } while (0); @@ -136,19 +133,15 @@ strcpy(stmt->error_code, "HY000"); H->last_app_error = "Cannot fetch from a closed cursor"; } else if (!S->exhausted) { - - /* an EXECUTE PROCEDURE statement can be fetched from once, without calling the API, because - * the result was returned in the execute call */ + if (isc_dsql_fetch(H->isc_status, &S->stmt, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) { + if (H->isc_status[0] && H->isc_status[1]) { + RECORD_ERROR(stmt); + } + S->exhausted = 1; + return 0; + } if (S->statement_type == isc_info_sql_stmt_exec_procedure) { S->exhausted = 1; - } else { - if (isc_dsql_fetch(H->isc_status, &S->stmt, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) { - if (H->isc_status[0] && H->isc_status[1]) { - RECORD_ERROR(stmt); - } - S->exhausted = 1; - return 0; - } } return 1; } @@ -172,8 +165,10 @@ colname_len = (S->H->fetch_table_names && var->relname_length) ? (var->aliasname_length + var->relname_length + 1) : (var->aliasname_length); - col->precision = -var->sqlscale; + col->precision = -var->sqlscale; col->maxlen = var->sqllen; + col->relname = (var->relname_length ? estrndup(var->relname, var->relname_length) : NULL); + col->relnamelen = var->relname_length; col->namelen = colname_len; col->name = cp = emalloc(colname_len + 1); if (colname_len > var->aliasname_length) { diff -u -r1.82.2.31.2.17.2.2 pdo_dbh.c --- ext/pdo/pdo_dbh.c 7 Oct 2007 05:22:05 -0000 1.82.2.31.2.17.2.2 +++ ext/pdo/pdo_dbh.c 19 Nov 2007 19:46:54 -0000 @@ -784,6 +784,13 @@ return SUCCESS; } + case PDO_ATTR_2D_NULLBASE: + if( dbh->nullbase ) { + efree( dbh->nullbase ); + } + dbh->nullbase = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); + return SUCCESS; + default: ; } @@ -872,6 +879,8 @@ case PDO_ATTR_DEFAULT_FETCH_MODE: RETURN_LONG(dbh->default_fetch_type); + case PDO_ATTR_2D_NULLBASE: + RETURN_STRING(dbh->nullbase, 1); } if (!dbh->methods->get_attribute) { @@ -1331,10 +1340,11 @@ REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST", (long)PDO_PARAM_EVT_FETCH_POST); REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE", (long)PDO_PARAM_EVT_NORMALIZE); - REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (long)PDO_FETCH_LAZY); REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC",(long)PDO_FETCH_ASSOC); REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM", (long)PDO_FETCH_NUM); REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (long)PDO_FETCH_BOTH); + REGISTER_PDO_CLASS_CONST_LONG("FETCH_2D", (long)PDO_FETCH_2D); + REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (long)PDO_FETCH_LAZY); REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ", (long)PDO_FETCH_OBJ); REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND",(long)PDO_FETCH_BOUND); REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN",(long)PDO_FETCH_COLUMN); @@ -1372,7 +1382,7 @@ REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN",(long)PDO_ATTR_MAX_COLUMN_LEN); REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES",(long)PDO_ATTR_EMULATE_PREPARES); REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE",(long)PDO_ATTR_DEFAULT_FETCH_MODE); - + REGISTER_PDO_CLASS_CONST_LONG("ATTR_2D_NULLBASE", (long)PDO_ATTR_2D_NULLBASE); REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT", (long)PDO_ERRMODE_SILENT); REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING", (long)PDO_ERRMODE_WARNING); REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION", (long)PDO_ERRMODE_EXCEPTION); @@ -1479,6 +1489,10 @@ dbh->properties = NULL; } + if( dbh->nullbase ) { + efree( dbh->nullbase ); + } + if (!dbh->is_persistent) { dbh_free(dbh TSRMLS_CC); } else if (dbh->methods && dbh->methods->persistent_shutdown) { @@ -1496,6 +1510,7 @@ memset(dbh, 0, sizeof(*dbh)); dbh->ce = ce; dbh->refcount = 1; + dbh->nullbase = NULL; ALLOC_HASHTABLE(dbh->properties); zend_hash_init(dbh->properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(dbh->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); diff -u -r1.118.2.38.2.24.2.5 pdo_stmt.c --- ext/pdo/pdo_stmt.c 31 Oct 2007 12:57:51 -0000 1.118.2.38.2.24.2.5 +++ ext/pdo/pdo_stmt.c 19 Nov 2007 19:46:54 -0000 @@ -894,6 +894,7 @@ int flags = how & PDO_FETCH_FLAGS, idx, old_arg_count = 0; zend_class_entry *ce = NULL, *old_ce = NULL; zval grp_val, *grp, **pgrp, *retval, *old_ctor_args = NULL; + zval *nullbase = NULL; if (how == PDO_FETCH_USE_DEFAULT) { how = stmt->default_fetch_type; @@ -925,6 +926,10 @@ case PDO_FETCH_BOTH: case PDO_FETCH_NUM: case PDO_FETCH_NAMED: + case PDO_FETCH_2D: + case PDO_FETCH_2D_NUM: + case PDO_FETCH_2D_ASSOC: + case PDO_FETCH_2D_BOTH: if (!return_all) { ALLOC_HASHTABLE(return_value->value.ht); zend_hash_init(return_value->value.ht, stmt->column_count, NULL, ZVAL_PTR_DTOR, 0); @@ -1060,10 +1065,59 @@ for (idx = 0; i < stmt->column_count; i++, idx++) { zval *val; + zval *base2d; MAKE_STD_ZVAL(val); fetch_value(stmt, val, i, NULL TSRMLS_CC); switch (how) { + case PDO_FETCH_2D: + case PDO_FETCH_2D_NUM: + case PDO_FETCH_2D_ASSOC: + case PDO_FETCH_2D_BOTH: + if( !nullbase && ((how & PDO_FETCH_BOTH) || !stmt->columns[i].relname) ) { + if( stmt->dbh->nullbase ) { + MAKE_STD_ZVAL(nullbase); + array_init(nullbase); + add_assoc_zval(return_value, stmt->dbh->nullbase, nullbase); + } + else { + nullbase = return_value; + } + } + + if( stmt->columns[i].relname ) { + zval **curr_val = NULL; + if (zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].relname, + stmt->columns[i].relnamelen+1, + (void**)&curr_val) == SUCCESS) { + if( Z_TYPE_PP(curr_val) != IS_ARRAY ) { + /* TODO: ERROR OUT OR NOT? */ + return 0; + } + base2d = *curr_val; + } + else { + MAKE_STD_ZVAL(base2d); + array_init(base2d); + add_assoc_zval(return_value, stmt->columns[i].relname, base2d); + } + } + else { + base2d = nullbase; + } + + add_assoc_zval(base2d, stmt->columns[i].name, val); + + if( how & PDO_FETCH_ASSOC ) { + Z_ADDREF_P(val); + add_assoc_zval(nullbase, stmt->columns[i].name, val); + } + if( how & PDO_FETCH_NUM ) { + Z_ADDREF_P(val); + add_next_index_zval(nullbase, val); + } + break; + case PDO_FETCH_ASSOC: add_assoc_zval(return_value, stmt->columns[i].name, val); break; @@ -2348,6 +2402,10 @@ efree(cols[i].name); cols[i].name = NULL; } + if (cols[i].relname) { + efree(cols[i].relname); + cols[i].relname = NULL; + } } efree(stmt->columns); stmt->columns = NULL; diff -u -r1.66.2.11.2.6.2.1 php_pdo_driver.h --- ext/pdo/php_pdo_driver.h 27 Sep 2007 18:00:42 -0000 1.66.2.11.2.6.2.1 +++ ext/pdo/php_pdo_driver.h 19 Nov 2007 19:46:54 -0000 @@ -79,10 +79,14 @@ enum pdo_fetch_type { PDO_FETCH_USE_DEFAULT, + PDO_FETCH_ASSOC, /* BEGIN */ + PDO_FETCH_NUM, /* All values from BEGIN to END are specially */ + PDO_FETCH_BOTH, /* arranged to be bitwise combineable. */ + PDO_FETCH_2D, /* e.g. ASSOC | NUM = BOTH */ + PDO_FETCH_2D_ASSOC, /* e.g. 2D | ASSOC = 2D_ASSOC */ + PDO_FETCH_2D_NUM, + PDO_FETCH_2D_BOTH, /* END */ PDO_FETCH_LAZY, - PDO_FETCH_ASSOC, - PDO_FETCH_NUM, - PDO_FETCH_BOTH, PDO_FETCH_OBJ, PDO_FETCH_BOUND, /* return true/false only; rely on bound columns */ PDO_FETCH_COLUMN, /* fetch a numbered column only */ @@ -133,6 +137,7 @@ PDO_ATTR_MAX_COLUMN_LEN, /* make database calculate maximum length of data found in a column */ PDO_ATTR_DEFAULT_FETCH_MODE, /* Set the default fetch mode */ PDO_ATTR_EMULATE_PREPARES, /* use query emulation rather than native */ + PDO_ATTR_2D_NULLBASE, /* array name for not further qualified columns */ /* this defines the start of the range for driver specific options. * Drivers should define their own attribute constants beginning with this @@ -470,6 +475,9 @@ * equal 32 */ unsigned _reserved_flags:21; + /* 2d nullbase */ + char *nullbase; + /* data source string used to open this handle */ const char *data_source; unsigned long data_source_len; @@ -508,6 +516,8 @@ /* describes a column */ struct pdo_column_data { + char *relname; + int relnamelen; char *name; int namelen; unsigned long maxlen; diff -u -r1.48.2.14.2.6 mysql_statement.c --- ext/pdo_mysql/mysql_statement.c 17 May 2007 15:12:23 -0000 1.48.2.14.2.6 +++ ext/pdo_mysql/mysql_statement.c 19 Nov 2007 19:46:54 -0000 @@ -454,6 +454,8 @@ cols[i].maxlen = S->fields[i].length; cols[i].namelen = namelen; cols[i].name = estrndup(S->fields[i].name, namelen); + cols[i].relnamelen = strlen(S->fields[i].table); /* TODO: WHERE are names efree'd? */ + cols[i].relname = (cols[i].relnamelen ? estrndup(S->fields[i].table, cols[i].relnamelen) : NULL); cols[i].param_type = PDO_PARAM_STR; } return 1;
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php