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

Reply via email to