Back to index

php5  5.3.10
oci8_statement.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Stig Sæther Bakken <ssb@php.net>                            |
00016    |          Thies C. Arntzen <thies@thieso.net>                         |
00017    |                                                                      |
00018    | Collection support by Andy Sautins <asautins@veripost.net>           |
00019    | Temporary LOB support by David Benson <dbenson@mancala.com>          |
00020    | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at>        |
00021    |                                                                      |
00022    | Redesigned by: Antony Dovgal <antony@zend.com>                       |
00023    |                Andi Gutmans <andi@zend.com>                          |
00024    |                Wez Furlong <wez@omniti.com>                          |
00025    +----------------------------------------------------------------------+
00026 */
00027 
00028 /* $Id: oci8_statement.c 321634 2012-01-01 13:15:04Z felipe $ */
00029 
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif
00034 
00035 #include "php.h"
00036 #include "ext/standard/info.h"
00037 #include "php_ini.h"
00038 
00039 #if HAVE_OCI8
00040 
00041 #include "php_oci8.h"
00042 #include "php_oci8_int.h"
00043 
00044 /* {{{ php_oci_statement_create()
00045  Create statemend handle and allocate necessary resources */
00046 php_oci_statement *php_oci_statement_create (php_oci_connection *connection, char *query, int query_len TSRMLS_DC)
00047 {
00048        php_oci_statement *statement;
00049        
00050        statement = ecalloc(1,sizeof(php_oci_statement));
00051 
00052        if (!query_len) {
00053               /* do not allocate stmt handle for refcursors, we'll get it from OCIStmtPrepare2() */
00054               PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->stmt), OCI_HTYPE_STMT, 0, NULL));
00055        }
00056                      
00057        PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->err), OCI_HTYPE_ERROR, 0, NULL));
00058        
00059        if (query_len > 0) {
00060               PHP_OCI_CALL_RETURN(connection->errcode, OCIStmtPrepare2,
00061                             (
00062                              connection->svc,
00063                              &(statement->stmt),
00064                              connection->err,
00065                              (text *)query,
00066                              query_len,
00067                              NULL,
00068                              0,
00069                              OCI_NTV_SYNTAX,
00070                              OCI_DEFAULT
00071                             )
00072               );
00073               if (connection->errcode != OCI_SUCCESS) {
00074                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00075 
00076                      PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, statement->errcode ? OCI_STRLS_CACHE_DELETE : OCI_DEFAULT));
00077                      PHP_OCI_CALL(OCIHandleFree,(statement->err, OCI_HTYPE_ERROR));
00078                      
00079                      efree(statement);
00080                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00081                      return NULL;
00082               }
00083        }
00084        
00085        if (query && query_len) {
00086               statement->last_query = estrndup(query, query_len);
00087               statement->last_query_len = query_len;
00088        }
00089        else {
00090               statement->last_query = NULL;
00091               statement->last_query_len = 0;
00092        }
00093 
00094        statement->connection = connection;
00095        statement->has_data = 0;
00096        statement->has_descr = 0;
00097        statement->parent_stmtid = 0;
00098        zend_list_addref(statement->connection->rsrc_id);
00099 
00100        if (OCI_G(default_prefetch) >= 0) {
00101               php_oci_statement_set_prefetch(statement, OCI_G(default_prefetch) TSRMLS_CC);
00102        }
00103        
00104        PHP_OCI_REGISTER_RESOURCE(statement, le_statement);
00105 
00106        OCI_G(num_statements)++;
00107        
00108        return statement;
00109 }
00110 /* }}} */
00111 
00112 /* {{{ php_oci_statement_set_prefetch()
00113  Set prefetch buffer size for the statement (we're assuming that one row is ~1K sized) */
00114 int php_oci_statement_set_prefetch(php_oci_statement *statement, long size TSRMLS_DC)
00115 {
00116        ub4 prefetch = size;
00117 
00118        if (size < 0) {
00119               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of rows to be prefetched has to be greater than or equal to 0");
00120               return 1;
00121        }
00122        
00123        PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrSet, (statement->stmt, OCI_HTYPE_STMT, &prefetch, 0, OCI_ATTR_PREFETCH_ROWS, statement->err));
00124        
00125        if (statement->errcode != OCI_SUCCESS) {
00126               statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00127               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00128               return 1;
00129        }
00130 
00131        return 0;
00132 }
00133 /* }}} */
00134 
00135 /* {{{ php_oci_cleanup_pre_fetch()
00136    Helper function to cleanup ref-cursors and descriptors from the previous row */
00137 int php_oci_cleanup_pre_fetch(void *data TSRMLS_DC)
00138 {
00139        php_oci_out_column *outcol = data;
00140 
00141        if (!outcol->is_descr && !outcol->is_cursor)
00142               return ZEND_HASH_APPLY_KEEP;
00143 
00144        switch(outcol->data_type) {
00145               case SQLT_CLOB:
00146               case SQLT_BLOB:
00147               case SQLT_RDD:
00148               case SQLT_BFILE:
00149                      if (outcol->descid) {
00150                             zend_list_delete(outcol->descid);
00151                             outcol->descid = 0;
00152                      }
00153                      break;
00154               case SQLT_RSET:
00155                      if (outcol->stmtid) {
00156                             zend_list_delete(outcol->stmtid);
00157                             outcol->stmtid = 0;
00158                             outcol->nested_statement = NULL;
00159                      }
00160                      break;
00161               default:
00162                      break;
00163        }
00164        return ZEND_HASH_APPLY_KEEP;
00165 
00166 } /* }}} */
00167 
00168 
00169 /* {{{ php_oci_statement_fetch()
00170  Fetch a row from the statement */
00171 int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows TSRMLS_DC)
00172 {
00173        int i;
00174        void *handlepp;
00175        ub4 typep, iterp, idxp;
00176        ub1 in_outp, piecep;
00177        zend_bool piecewisecols = 0;
00178 
00179        php_oci_out_column *column;
00180 
00181        if (statement->has_descr && statement->columns) {
00182               zend_hash_apply(statement->columns, (apply_func_t) php_oci_cleanup_pre_fetch TSRMLS_CC);
00183     }
00184 
00185        PHP_OCI_CALL_RETURN(statement->errcode, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
00186 
00187        if ( statement->errcode == OCI_NO_DATA || nrows == 0 ) {
00188               if (statement->last_query == NULL) {
00189                      /* reset define-list for refcursors */
00190                      if (statement->columns) {
00191                             zend_hash_destroy(statement->columns);
00192                             efree(statement->columns);
00193                             statement->columns = NULL;
00194                             statement->ncolumns = 0;
00195                      }
00196                      statement->executed = 0;
00197               }
00198 
00199               statement->errcode = 0; /* OCI_NO_DATA is NO error for us!!! */
00200               statement->has_data = 0;
00201 
00202               if (nrows == 0) {
00203                      /* this is exactly what we requested */
00204                      return 0;
00205               }
00206               return 1;
00207        }
00208 
00209        /* reset length for all piecewise columns */
00210        for (i = 0; i < statement->ncolumns; i++) {
00211               column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
00212               if (column->piecewise) {
00213                      column->retlen4 = 0;
00214                      piecewisecols = 1;
00215               }
00216        }
00217        
00218        while (statement->errcode == OCI_NEED_DATA) {
00219               if (piecewisecols) {
00220                      PHP_OCI_CALL_RETURN(statement->errcode,
00221                             OCIStmtGetPieceInfo,
00222                                (
00223                                    statement->stmt,
00224                                    statement->err,
00225                                    &handlepp,
00226                                    &typep,
00227                                    &in_outp,
00228                                    &iterp,
00229                                    &idxp,
00230                                    &piecep
00231                                )
00232                      );
00233 
00234                      /* scan through our columns for a piecewise column with a matching handle */
00235                      for (i = 0; i < statement->ncolumns; i++) {
00236                             column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
00237                             if (column->piecewise && handlepp == column->oci_define)   {
00238                                    if (!column->data) {
00239                                           column->data = (text *) ecalloc(1, PHP_OCI_PIECE_SIZE + 1);
00240                                    } else {
00241                                           column->data = erealloc(column->data, column->retlen4 + PHP_OCI_PIECE_SIZE + 1);
00242                                    }
00243                                    column->cb_retlen = PHP_OCI_PIECE_SIZE;
00244 
00245                                    /* and instruct fetch to fetch waiting piece into our buffer */
00246                                    PHP_OCI_CALL(OCIStmtSetPieceInfo,
00247                                              (
00248                                                  (void *) column->oci_define,
00249                                                  OCI_HTYPE_DEFINE,
00250                                                  statement->err,
00251                                                  ((char*)column->data) + column->retlen4,
00252                                                  &(column->cb_retlen),
00253                                                  piecep,
00254                                                  &column->indicator,
00255                                                  &column->retcode
00256                                              )
00257                                    );
00258                             }
00259                      }
00260               }
00261 
00262               PHP_OCI_CALL_RETURN(statement->errcode,    OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
00263 
00264               if (piecewisecols) {
00265                      for (i = 0; i < statement->ncolumns; i++) {
00266                             column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
00267                             if (column && column->piecewise && handlepp == column->oci_define)    {
00268                                    column->retlen4 += column->cb_retlen;
00269                             }
00270                      }
00271               }
00272        }
00273 
00274        if (statement->errcode == OCI_SUCCESS_WITH_INFO || statement->errcode == OCI_SUCCESS) {
00275               statement->has_data = 1;
00276 
00277               /* do the stuff needed for OCIDefineByName */
00278               for (i = 0; i < statement->ncolumns; i++) {
00279                      column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
00280                      if (column == NULL) {
00281                             continue;
00282                      }
00283                      
00284                      if (!column->define) {
00285                             continue;
00286                      }
00287                      
00288                      zval_dtor(column->define->zval);
00289                      php_oci_column_to_zval(column, column->define->zval, 0 TSRMLS_CC);
00290               }
00291 
00292               return 0;
00293        }
00294 
00295        statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00296        PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00297 
00298        statement->has_data = 0;
00299 
00300        return 1;
00301 }
00302 /* }}} */
00303 
00304 /* {{{ php_oci_statement_get_column()
00305  Get column from the result set */
00306 php_oci_out_column *php_oci_statement_get_column(php_oci_statement *statement, long column_index, char *column_name, int column_name_len TSRMLS_DC)
00307 {
00308        php_oci_out_column *column = NULL;
00309        int i;
00310 
00311        if (statement->columns == NULL) { /* we release the columns at the end of a fetch */
00312               return NULL;
00313        }
00314 
00315        if (column_name) {
00316               for (i = 0; i < statement->ncolumns; i++) {
00317                      column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
00318                      if (column == NULL) {
00319                             continue;
00320                      } else if (((int) column->name_len == column_name_len) && (!strncmp(column->name, column_name, column_name_len))) {
00321                             return column;
00322                      }
00323               }
00324        } else if (column_index != -1) {
00325               if (zend_hash_index_find(statement->columns, column_index, (void **)&column) == FAILURE) {
00326                      return NULL;
00327               }
00328               return column;
00329        }
00330 
00331        return NULL;
00332 }
00333 /* }}} */
00334 
00335 /* php_oci_define_callback() {{{ */
00336 sb4 php_oci_define_callback(dvoid *ctx, OCIDefine *define, ub4 iter, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
00337 {
00338        php_oci_out_column *outcol = (php_oci_out_column *)ctx;
00339        TSRMLS_FETCH();
00340 
00341        if (!outcol) {
00342               
00343               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid context pointer value");
00344               return OCI_ERROR;
00345        }
00346        
00347        switch(outcol->data_type) {
00348               case SQLT_RSET: {
00349                             php_oci_statement *nested_stmt;
00350 
00351                             nested_stmt = php_oci_statement_create(outcol->statement->connection, NULL, 0 TSRMLS_CC);
00352                             if (!nested_stmt) {
00353                                    return OCI_ERROR;
00354                             }
00355                             nested_stmt->parent_stmtid = outcol->statement->id;
00356                             zend_list_addref(outcol->statement->id);
00357                             outcol->nested_statement = nested_stmt;
00358                             outcol->stmtid = nested_stmt->id;
00359 
00360                             *bufpp = nested_stmt->stmt;
00361                             *alenpp = &(outcol->retlen4);
00362                             *piecep = OCI_ONE_PIECE;
00363                             *indpp = &(outcol->indicator);
00364                             *rcpp = &(outcol->retcode);
00365                             return OCI_CONTINUE;
00366                      }
00367                      break;
00368               case SQLT_RDD:
00369               case SQLT_BLOB:
00370               case SQLT_CLOB:
00371               case SQLT_BFILE: {
00372                             php_oci_descriptor *descr;
00373                             int dtype;
00374 
00375                             if (outcol->data_type == SQLT_BFILE) {
00376                                    dtype = OCI_DTYPE_FILE;
00377                             } else if (outcol->data_type == SQLT_RDD ) {
00378                                    dtype = OCI_DTYPE_ROWID;
00379                             } else {
00380                                    dtype = OCI_DTYPE_LOB;
00381                             }
00382 
00383                             descr = php_oci_lob_create(outcol->statement->connection, dtype TSRMLS_CC);
00384                             if (!descr) {
00385                                    return OCI_ERROR;
00386                             }
00387                             outcol->descid = descr->id;
00388                             descr->charset_form = outcol->charset_form;
00389                             
00390                             *bufpp = descr->descriptor;
00391                             *alenpp = &(outcol->retlen4);
00392                             *piecep = OCI_ONE_PIECE;
00393                             *indpp = &(outcol->indicator);
00394                             *rcpp = &(outcol->retcode);
00395 
00396                             return OCI_CONTINUE;
00397                      }
00398                      break;
00399        }
00400        return OCI_ERROR;
00401 }
00402 /* }}} */
00403 
00404 /* {{{ php_oci_statement_execute()
00405  Execute statement */
00406 int php_oci_statement_execute(php_oci_statement *statement, ub4 mode TSRMLS_DC)
00407 {
00408        php_oci_out_column *outcol;
00409        php_oci_out_column column;
00410        OCIParam *param = NULL;
00411        text *colname;
00412        ub4 counter;
00413        ub2 define_type;
00414        ub4 iters;
00415        ub4 colcount;
00416        ub2 dynamic;
00417        dvoid *buf;
00418 
00419        switch (mode) {
00420               case OCI_COMMIT_ON_SUCCESS:
00421               case OCI_DESCRIBE_ONLY:
00422               case OCI_DEFAULT:
00423                      /* only these are allowed */
00424                      break;
00425               default:
00426                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid execute mode given: %d", mode);
00427                      return 1;
00428                      break;
00429        }
00430        
00431        if (!statement->stmttype) {
00432               /* get statement type */
00433               PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement->stmttype, (ub4 *)0,       OCI_ATTR_STMT_TYPE,  statement->err));
00434 
00435               if (statement->errcode != OCI_SUCCESS) {
00436                      statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00437                      PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00438                      return 1;
00439               }
00440        }
00441 
00442        if (statement->stmttype == OCI_STMT_SELECT) {
00443               iters = 0;
00444        } else {
00445               iters = 1;
00446        }
00447        
00448        if (statement->last_query) {
00449               /* if we execute refcursors we don't have a query and
00450                  we don't want to execute!!! */
00451 
00452               if (statement->binds) {
00453                      int result = 0;
00454                      zend_hash_apply_with_argument(statement->binds, (apply_func_arg_t) php_oci_bind_pre_exec, (void *)&result TSRMLS_CC);
00455                      if (result) {
00456                             return 1;
00457                      }
00458               }
00459 
00460               /* execute statement */
00461               PHP_OCI_CALL_RETURN(statement->errcode, OCIStmtExecute, (statement->connection->svc,       statement->stmt, statement->err, iters,   0, NULL, NULL, mode));
00462 
00463               if (statement->errcode != OCI_SUCCESS) {
00464                      statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00465                      PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00466                      return 1;
00467               }
00468               
00469               if (statement->binds) {
00470                      zend_hash_apply(statement->binds, (apply_func_t) php_oci_bind_post_exec TSRMLS_CC);
00471               }
00472 
00473               if (mode & OCI_COMMIT_ON_SUCCESS) {
00474                      statement->connection->needs_commit = 0;
00475               } else {
00476                      statement->connection->needs_commit = 1;
00477               }
00478        }
00479 
00480        if (statement->stmttype == OCI_STMT_SELECT && statement->executed == 0) {
00481               /* we only need to do the define step is this very statement is executed the first time! */
00482               statement->executed = 1;
00483               
00484               ALLOC_HASHTABLE(statement->columns);
00485               zend_hash_init(statement->columns, 13, NULL, php_oci_column_hash_dtor, 0);
00486               
00487               counter = 1;
00488 
00489               /* get number of columns */
00490               PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *)&colcount, (ub4 *)0, OCI_ATTR_PARAM_COUNT, statement->err));
00491               
00492               if (statement->errcode != OCI_SUCCESS) {
00493                      statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00494                      PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00495                      return 1;
00496               }
00497 
00498               statement->ncolumns = colcount;
00499               
00500               for (counter = 1; counter <= colcount; counter++) {
00501                      memset(&column,0,sizeof(php_oci_out_column));
00502                      
00503                      if (zend_hash_index_update(statement->columns, counter, &column, sizeof(php_oci_out_column), (void**) &outcol) == FAILURE) {
00504                             efree(statement->columns);
00505                             /* out of memory */
00506                             return 1;
00507                      }
00508                      
00509                      /* get column */
00510                      PHP_OCI_CALL_RETURN(statement->errcode, OCIParamGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, statement->err, (dvoid**)&param, counter));
00511                      
00512                      if (statement->errcode != OCI_SUCCESS) {
00513                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00514                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00515                             return 1;
00516                      }
00517 
00518                      /* get column datatype */
00519                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_type, (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->err));
00520 
00521                      if (statement->errcode != OCI_SUCCESS) {
00522                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00523                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00524                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00525                             return 1;
00526                      }
00527 
00528                      /* get character set form  */
00529                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_form, (ub4 *)0, OCI_ATTR_CHARSET_FORM, statement->err));
00530 
00531                      if (statement->errcode != OCI_SUCCESS) {
00532                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00533                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00534                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00535                             return 1;
00536                      }
00537        
00538                      /* get character set id      */
00539                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_id, (ub4 *)0, OCI_ATTR_CHARSET_ID, statement->err));
00540 
00541                      if (statement->errcode != OCI_SUCCESS) {
00542                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00543                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00544                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00545                             return 1;
00546                      }
00547        
00548                      /* get size of the column */
00549                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_size, (dvoid *)0, OCI_ATTR_DATA_SIZE, statement->err));
00550                      
00551                      if (statement->errcode != OCI_SUCCESS) {
00552                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00553                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00554                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00555                             return 1;
00556                      }
00557 
00558                      outcol->storage_size4 = outcol->data_size;
00559                      outcol->retlen = outcol->data_size;
00560 
00561                      /* get scale of the column */
00562                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->scale, (dvoid *)0, OCI_ATTR_SCALE, statement->err));
00563                      
00564                      if (statement->errcode != OCI_SUCCESS) {
00565                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00566                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00567                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00568                             return 1;
00569                      }
00570 
00571                      /* get precision of the column */
00572                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->precision, (dvoid *)0, OCI_ATTR_PRECISION, statement->err));
00573                      
00574                      if (statement->errcode != OCI_SUCCESS) {
00575                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00576                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00577                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00578                             return 1;
00579                      }
00580                      
00581                      /* get name of the column */
00582                      PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid **)&colname, (ub4 *)&outcol->name_len, (ub4)OCI_ATTR_NAME, statement->err));
00583                      
00584                      if (statement->errcode != OCI_SUCCESS) {
00585                             PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00586                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00587                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00588                             return 1;
00589                      }
00590                      PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
00591 
00592                      outcol->name = estrndup((char*) colname, outcol->name_len);
00593 
00594                      /* find a user-setted define */
00595                      if (statement->defines) {
00596                             if (zend_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define) == SUCCESS) {
00597                                    if (outcol->define->type) {
00598                                           outcol->data_type = outcol->define->type;
00599                                    }
00600                             }
00601                      }
00602 
00603                      buf = 0;
00604                      switch (outcol->data_type) {
00605                             case SQLT_RSET:
00606                                    outcol->statement = statement; /* parent handle */
00607 
00608                                    define_type = SQLT_RSET;
00609                                    outcol->is_cursor = 1;
00610                                    outcol->statement->has_descr = 1;
00611                                    outcol->storage_size4 = -1;
00612                                    outcol->retlen = -1;
00613                                    dynamic = OCI_DYNAMIC_FETCH;
00614                                    break;
00615 
00616                             case SQLT_RDD:        /* ROWID */
00617                             case SQLT_BLOB:       /* binary LOB */
00618                             case SQLT_CLOB:       /* character LOB */
00619                             case SQLT_BFILE: /* binary file LOB */
00620                                    outcol->statement = statement; /* parent handle */
00621 
00622                                    define_type = outcol->data_type;
00623                                    outcol->is_descr = 1;
00624                                    outcol->statement->has_descr = 1;
00625                                    outcol->storage_size4 = -1;
00626                                    dynamic = OCI_DYNAMIC_FETCH;
00627                                    break;
00628 
00629                             case SQLT_LNG:
00630                             case SQLT_LBI:
00631                                    if (outcol->data_type == SQLT_LBI) {
00632                                           define_type = SQLT_BIN;
00633                                    } else {
00634                                           define_type = SQLT_CHR;
00635                                    }
00636                                    outcol->storage_size4 = PHP_OCI_MAX_DATA_SIZE;
00637                                    outcol->piecewise = 1;
00638                                    dynamic = OCI_DYNAMIC_FETCH;
00639                                    break;
00640 
00641                             case SQLT_BIN:
00642                             default:
00643                                    define_type = SQLT_CHR;
00644                                    if (outcol->data_type == SQLT_BIN) {
00645                                           define_type = SQLT_BIN;
00646                                    }
00647                                    if ((outcol->data_type == SQLT_DAT) || (outcol->data_type == SQLT_NUM)
00648 #ifdef SQLT_TIMESTAMP
00649                                           || (outcol->data_type == SQLT_TIMESTAMP)
00650 #endif
00651 #ifdef SQLT_TIMESTAMP_TZ
00652                                           || (outcol->data_type == SQLT_TIMESTAMP_TZ)
00653 #endif
00654 #ifdef SQLT_TIMESTAMP_LTZ
00655                                           || (outcol->data_type == SQLT_TIMESTAMP_LTZ)
00656 #endif
00657 #ifdef SQLT_INTERVAL_YM
00658                                           || (outcol->data_type == SQLT_INTERVAL_YM)
00659 #endif
00660 #ifdef SQLT_INTERVAL_DS
00661                                           || (outcol->data_type == SQLT_INTERVAL_DS)
00662 #endif
00663                                           ) {
00664                                           outcol->storage_size4 = 512; /* XXX this should fit "most" NLS date-formats and Numbers */
00665 #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
00666                                    } else if (outcol->data_type == SQLT_IBFLOAT || outcol->data_type == SQLT_IBDOUBLE) {
00667                                           outcol->storage_size4 = 1024;
00668 #endif
00669                                    } else {
00670                                           outcol->storage_size4++; /* add one for string terminator */
00671                                    }
00672                                    
00673                                    outcol->storage_size4 *= 3;
00674                                    
00675                                    dynamic = OCI_DEFAULT;
00676                                    buf = outcol->data = (text *) safe_emalloc(1, outcol->storage_size4, 0);
00677                                    memset(buf, 0, outcol->storage_size4);
00678                                    break;
00679                      }
00680 
00681                      if (dynamic == OCI_DYNAMIC_FETCH) {
00682                             PHP_OCI_CALL_RETURN(statement->errcode,
00683                                    OCIDefineByPos,
00684                                    (
00685                                           statement->stmt,                                               /* IN/OUT handle to the requested SQL query */
00686                                           (OCIDefine **)&outcol->oci_define,               /* IN/OUT pointer to a pointer to a define handle */
00687                                           statement->err,                                                       /* IN/OUT An error handle  */
00688                                           counter,                                                              /* IN    position in the select list */
00689                                           (dvoid *)NULL,                                                        /* IN/OUT pointer to a buffer */
00690                                           outcol->storage_size4,                                         /* IN    The size of each valuep buffer in bytes */
00691                                           define_type,                                                   /* IN    The data type */
00692                                           (dvoid *)&outcol->indicator,                            /* IN    pointer to an indicator variable or arr */
00693                                           (ub2 *)NULL,                                                   /* IN/OUT Pointer to array of length of data fetched */
00694                                           (ub2 *)NULL,                                                   /* OUT   Pointer to array of column-level return codes */
00695                                           OCI_DYNAMIC_FETCH                                              /* IN    mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
00696                                    )
00697                             );
00698 
00699                      } else {
00700                             PHP_OCI_CALL_RETURN(statement->errcode,
00701                                    OCIDefineByPos,
00702                                    (
00703                                           statement->stmt,                                               /* IN/OUT handle to the requested SQL query */
00704                                           (OCIDefine **)&outcol->oci_define,               /* IN/OUT pointer to a pointer to a define handle */
00705                                           statement->err,                                                       /* IN/OUT An error handle  */
00706                                           counter,                                                              /* IN    position in the select list */
00707                                           (dvoid *)buf,                                                  /* IN/OUT pointer to a buffer */
00708                                           outcol->storage_size4,                                         /* IN    The size of each valuep buffer in bytes */
00709                                           define_type,                                                   /* IN    The data type */
00710                                           (dvoid *)&outcol->indicator,                            /* IN    pointer to an indicator variable or arr */
00711                                           (ub2 *)&outcol->retlen,                                        /* IN/OUT Pointer to array of length of data fetched */
00712                                           (ub2 *)&outcol->retcode,                                /* OUT   Pointer to array of column-level return codes */
00713                                           OCI_DEFAULT                                                           /* IN    mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
00714                                    )
00715                             );
00716 
00717                      }
00718                      
00719                      if (statement->errcode != OCI_SUCCESS) {
00720                             statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
00721                             PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
00722                             return 0;
00723                      }
00724 
00725                      /* additional OCIDefineDynamic() call */
00726                      switch (outcol->data_type) {
00727                             case SQLT_RSET:
00728                             case SQLT_RDD:
00729                             case SQLT_BLOB:
00730                             case SQLT_CLOB:
00731                             case SQLT_BFILE:
00732                                    PHP_OCI_CALL_RETURN(statement->errcode,
00733                                           OCIDefineDynamic,
00734                                           (
00735                                                  outcol->oci_define,
00736                                                  statement->err,
00737                                                  (dvoid *)outcol,
00738                                                  php_oci_define_callback
00739                                           )
00740                                    );
00741 
00742                                    break;
00743                      }
00744               }
00745        }
00746 
00747        return 0;
00748 }
00749 /* }}} */
00750 
00751 /* {{{ php_oci_statement_cancel()
00752  Cancel statement */
00753 int php_oci_statement_cancel(php_oci_statement *statement TSRMLS_DC)
00754 {
00755        
00756        return php_oci_statement_fetch(statement, 0 TSRMLS_CC);
00757               
00758 } /* }}} */
00759 
00760 /* {{{ php_oci_statement_free()
00761  Destroy statement handle and free associated resources */
00762 void php_oci_statement_free(php_oci_statement *statement TSRMLS_DC)
00763 {
00764        if (statement->stmt) {
00765               if (statement->last_query_len) { /* FIXME: magical */
00766                      PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, statement->errcode ? OCI_STRLS_CACHE_DELETE : OCI_DEFAULT));
00767               } else {
00768                      PHP_OCI_CALL(OCIHandleFree, (statement->stmt, OCI_HTYPE_STMT));
00769               }
00770               statement->stmt = 0;
00771        }
00772 
00773        if (statement->err) {
00774               PHP_OCI_CALL(OCIHandleFree, (statement->err, OCI_HTYPE_ERROR));
00775               statement->err = 0;
00776        }
00777 
00778        if (statement->last_query) {
00779               efree(statement->last_query);
00780        }
00781 
00782        if (statement->columns) {
00783               zend_hash_destroy(statement->columns);
00784               efree(statement->columns);
00785        }
00786 
00787        if (statement->binds) {
00788               zend_hash_destroy(statement->binds);
00789               efree(statement->binds);
00790        }
00791 
00792        if (statement->defines) {
00793               zend_hash_destroy(statement->defines);
00794               efree(statement->defines);
00795        }
00796 
00797        if (statement->parent_stmtid) {
00798               zend_list_delete(statement->parent_stmtid);
00799        }
00800 
00801        zend_list_delete(statement->connection->rsrc_id);
00802        efree(statement);
00803        
00804        OCI_G(num_statements)--;
00805 } /* }}} */
00806 
00807 /* {{{ php_oci_bind_pre_exec()
00808  Helper function */
00809 int php_oci_bind_pre_exec(void *data, void *result TSRMLS_DC)
00810 {
00811        php_oci_bind *bind = (php_oci_bind *) data;
00812 
00813        *(int *)result = 0;
00814 
00815        if (Z_TYPE_P(bind->zval) == IS_ARRAY) {
00816               /* These checks are currently valid for oci_bind_by_name, not
00817                * oci_bind_array_by_name.  Also bind->type and
00818                * bind->indicator are not used for oci_bind_array_by_name.
00819                */
00820               return 0;
00821        }      
00822        switch (bind->type) {
00823               case SQLT_NTY:
00824               case SQLT_BFILEE:
00825               case SQLT_CFILEE:
00826               case SQLT_CLOB:
00827               case SQLT_BLOB:
00828               case SQLT_RDD:
00829                      if (Z_TYPE_P(bind->zval) != IS_OBJECT) {
00830                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
00831                             *(int *)result = 1;
00832                      }
00833                      break;
00834                      
00835               case SQLT_INT:
00836               case SQLT_NUM:
00837                      if (Z_TYPE_P(bind->zval) == IS_RESOURCE || Z_TYPE_P(bind->zval) == IS_OBJECT) {
00838                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
00839                             *(int *)result = 1;
00840                      }
00841                      break;
00842                      
00843               case SQLT_LBI:
00844               case SQLT_BIN:
00845               case SQLT_LNG:
00846               case SQLT_AFC:
00847               case SQLT_CHR:
00848                      if (Z_TYPE_P(bind->zval) == IS_RESOURCE || Z_TYPE_P(bind->zval) == IS_OBJECT) {
00849                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
00850                             *(int *)result = 1;
00851                      }
00852                      break;
00853 
00854               case SQLT_RSET:
00855                      if (Z_TYPE_P(bind->zval) != IS_RESOURCE) {
00856                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
00857                             *(int *)result = 1;
00858                      }
00859                      break;
00860        }
00861 
00862        /* reset all bind stuff to a normal state..-. */
00863        bind->indicator = 0;
00864 
00865        return 0;
00866 }
00867 /* }}} */
00868 
00869 /* {{{ php_oci_bind_post_exec()
00870  Helper function */
00871 int php_oci_bind_post_exec(void *data TSRMLS_DC)
00872 {
00873        php_oci_bind *bind = (php_oci_bind *) data;
00874        php_oci_connection *connection = bind->parent_statement->connection;
00875 
00876        if (bind->indicator == -1) { /* NULL */
00877               zval *val = bind->zval;
00878               if (Z_TYPE_P(val) == IS_STRING) {
00879                      *Z_STRVAL_P(val) = '\0'; /* XXX avoid warning in debug mode */
00880               }
00881               zval_dtor(val);
00882               ZVAL_NULL(val);
00883        } else if (Z_TYPE_P(bind->zval) == IS_STRING
00884                         && Z_STRLEN_P(bind->zval) > 0
00885                         && Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] != '\0') {
00886               /* The post- PHP 5.3 feature for "interned" strings disallows
00887                * their reallocation but (i) any IN binds either interned or
00888                * not should already be null terminated and (ii) for OUT
00889                * binds, php_oci_bind_out_callback() should have allocated a
00890                * new string that we can modify here.
00891                */
00892               Z_STRVAL_P(bind->zval) = erealloc(Z_STRVAL_P(bind->zval), Z_STRLEN_P(bind->zval)+1);
00893               Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] = '\0';
00894        } else if (Z_TYPE_P(bind->zval) == IS_ARRAY) {
00895               int i;
00896               zval **entry;
00897               HashTable *hash = HASH_OF(bind->zval);
00898        
00899               zend_hash_internal_pointer_reset(hash);
00900 
00901               switch (bind->array.type) {
00902                      case SQLT_NUM:
00903                      case SQLT_INT:
00904                      case SQLT_LNG:
00905                             for (i = 0; i < bind->array.current_length; i++) {
00906                                    if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
00907                                           zval_dtor(*entry);
00908                                           ZVAL_LONG(*entry, ((ub4 *)(bind->array.elements))[i]);
00909                                           zend_hash_move_forward(hash);
00910                                    } else {
00911                                           add_next_index_long(bind->zval, ((ub4 *)(bind->array.elements))[i]);
00912                                    }
00913                             }
00914                             break;
00915                      case SQLT_FLT:
00916                             for (i = 0; i < bind->array.current_length; i++) {
00917                                    if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
00918                                           zval_dtor(*entry);
00919                                           ZVAL_DOUBLE(*entry, ((double *)(bind->array.elements))[i]);
00920                                           zend_hash_move_forward(hash);
00921                                    } else {
00922                                           add_next_index_double(bind->zval, ((double *)(bind->array.elements))[i]);
00923                                    }
00924                             }
00925                             break;
00926                      case SQLT_ODT:
00927                             for (i = 0; i < bind->array.current_length; i++) {
00928                                    oratext buff[1024];
00929                                    ub4 buff_len = 1024;
00930 
00931                                    memset((void*)buff,0,sizeof(buff));
00932                                                  
00933                                    if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
00934                                           PHP_OCI_CALL_RETURN(connection->errcode, OCIDateToText, (connection->err, &(((OCIDate *)(bind->array.elements))[i]), 0, 0, 0, 0, &buff_len, buff));
00935                                           zval_dtor(*entry);
00936 
00937                                           if (connection->errcode != OCI_SUCCESS) {
00938                                                  connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00939                                                  PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00940                                                  ZVAL_NULL(*entry);
00941                                           } else {
00942                                                  ZVAL_STRINGL(*entry, (char *)buff, buff_len, 1);
00943                                           }
00944                                           zend_hash_move_forward(hash);
00945                                    } else {
00946                                           PHP_OCI_CALL_RETURN(connection->errcode, OCIDateToText, (connection->err, &(((OCIDate *)(bind->array.elements))[i]), 0, 0, 0, 0, &buff_len, buff));
00947                                           if (connection->errcode != OCI_SUCCESS) {
00948                                                  connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00949                                                  PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00950                                                  add_next_index_null(bind->zval);
00951                                           } else {
00952                                                  add_next_index_stringl(bind->zval, (char *)buff, buff_len, 1);
00953                                           }
00954                                    }
00955                             }
00956                             break;
00957        
00958                      case SQLT_AFC:
00959                      case SQLT_CHR:
00960                      case SQLT_VCS:
00961                      case SQLT_AVC:
00962                      case SQLT_STR:
00963                      case SQLT_LVC:
00964                             for (i = 0; i < bind->array.current_length; i++) {
00965                                    /* int curr_element_length = strlen(((text *)bind->array.elements)+i*bind->array.max_length); */
00966                                    int curr_element_length = bind->array.element_lengths[i];
00967                                    if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
00968                                           zval_dtor(*entry);
00969                                           ZVAL_STRINGL(*entry, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length, 1);
00970                                           zend_hash_move_forward(hash);
00971                                    } else {
00972                                           add_next_index_stringl(bind->zval, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length, 1);
00973                                    }
00974                             }
00975                             break;
00976               }
00977        }
00978 
00979        return 0;
00980 }
00981 /* }}} */
00982 
00983 /* {{{ php_oci_bind_by_name()
00984  Bind zval to the given placeholder */
00985 int php_oci_bind_by_name(php_oci_statement *statement, char *name, int name_len, zval* var, long maxlength, ub2 type TSRMLS_DC)
00986 {
00987        php_oci_collection *bind_collection = NULL;
00988        php_oci_descriptor *bind_descriptor = NULL;
00989        php_oci_statement  *bind_statement = NULL;
00990        dvoid *oci_desc                                  = NULL;
00991        /* dvoid *php_oci_collection                 = NULL; */
00992        OCIStmt *oci_stmt                         = NULL;
00993        dvoid *bind_data                          = NULL;
00994        php_oci_bind bind, *old_bind, *bindp;
00995        int mode = OCI_DATA_AT_EXEC;
00996        sb4 value_sz = -1;
00997 
00998        switch (type) {
00999               case SQLT_NTY:
01000               {
01001                      zval **tmp;
01002                      
01003                      if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
01004                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
01005                             return 1;
01006                      }
01007 
01008                      PHP_OCI_ZVAL_TO_COLLECTION_EX(*tmp, bind_collection);
01009                      value_sz = sizeof(void*);
01010                      mode = OCI_DEFAULT;
01011               
01012                      if (!bind_collection->collection) {
01013                             return 1;
01014                      }
01015               }
01016                      break;
01017               case SQLT_BFILEE:
01018               case SQLT_CFILEE:
01019               case SQLT_CLOB:
01020               case SQLT_BLOB:
01021               case SQLT_RDD:
01022               {
01023                      zval **tmp;
01024                      
01025                      if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
01026                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
01027                             return 1;
01028                      }
01029 
01030                      PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, bind_descriptor);
01031 
01032                      value_sz = sizeof(void*);
01033                      
01034                      oci_desc = bind_descriptor->descriptor;
01035                      
01036                      if (!oci_desc) {
01037                             return 1;
01038                      }
01039               }
01040                      break;
01041                      
01042               case SQLT_INT:
01043               case SQLT_NUM:
01044                      if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
01045                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
01046                             return 1;
01047                      }
01048                      convert_to_long(var);
01049                      bind_data = (ub4 *)&Z_LVAL_P(var);
01050                      value_sz = sizeof(ub4);
01051                      mode = OCI_DEFAULT;
01052                      break;
01053                      
01054               case SQLT_LBI:
01055               case SQLT_BIN:
01056               case SQLT_LNG:
01057               case SQLT_AFC:
01058               case SQLT_CHR: /* SQLT_CHR is the default value when type was not specified */
01059                      if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
01060                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
01061                             return 1;
01062                      }
01063                      if (Z_TYPE_P(var) != IS_NULL) {
01064                             convert_to_string(var);
01065                      }
01066                      if (maxlength == -1) {
01067                             value_sz = (Z_TYPE_P(var) == IS_STRING) ? Z_STRLEN_P(var) : 0;
01068                      } else {
01069                             value_sz = maxlength;
01070                      }
01071                      break;
01072 
01073               case SQLT_RSET:
01074                      if (Z_TYPE_P(var) != IS_RESOURCE) {
01075                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
01076                             return 1;
01077                      }
01078                      PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement);
01079                      value_sz = sizeof(void*);
01080 
01081                      oci_stmt = bind_statement->stmt;
01082 
01083                      if (!oci_stmt) {
01084                             return 1;
01085                      }
01086                      break;
01087 
01088               default:
01089                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %d", (int)type);
01090                      return 1;
01091                      break;
01092        }
01093        
01094        if (value_sz == 0) {
01095               value_sz = 1;
01096        }
01097        
01098        if (!statement->binds) {
01099               ALLOC_HASHTABLE(statement->binds);
01100               zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
01101        }
01102 
01103        memset((void*)&bind,0,sizeof(php_oci_bind));
01104        if (zend_hash_find(statement->binds, name, name_len + 1, (void **)&old_bind) == SUCCESS) {
01105               bindp = old_bind;
01106               if (bindp->zval) {
01107                      zval_ptr_dtor(&bindp->zval);
01108               }
01109        } else {
01110               zend_hash_update(statement->binds, name, name_len + 1, &bind, sizeof(php_oci_bind), (void **)&bindp);
01111        }
01112        
01113        bindp->descriptor = oci_desc;
01114        bindp->statement = oci_stmt;
01115        bindp->parent_statement = statement;
01116        bindp->zval = var;
01117        bindp->type = type;
01118        zval_add_ref(&var);
01119        
01120        PHP_OCI_CALL_RETURN(statement->errcode,
01121               OCIBindByName,
01122               (
01123                      statement->stmt,                           /* statement handle */
01124                      (OCIBind **)&bindp->bind,           /* bind hdl (will alloc) */
01125                      statement->err,                                   /* error handle */
01126                      (text*) name,                              /* placeholder name */                                 
01127                      name_len,                                         /* placeholder length */
01128                      (dvoid *)bind_data,                        /* in/out data */
01129                      value_sz, /* PHP_OCI_MAX_DATA_SIZE, */ /* max size of input/output data */
01130                      type,                                             /* in/out data type */
01131                      (dvoid *)&bindp->indicator,         /* indicator (ignored) */
01132                      (ub2 *)0,                                         /* size array (ignored) */
01133                      (ub2 *)&bindp->retcode,                    /* return code (ignored) */
01134                      (ub4)0,                                                  /* maxarr_len (PL/SQL only?) */
01135                      (ub4 *)0,                                         /* actual array size (PL/SQL only?) */
01136                      mode                                              /* mode */
01137               )
01138        );
01139 
01140        if (statement->errcode != OCI_SUCCESS) {
01141               statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
01142               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
01143               return 1;
01144        }
01145 
01146        if (mode == OCI_DATA_AT_EXEC) {
01147               PHP_OCI_CALL_RETURN(statement->errcode, OCIBindDynamic,
01148                             (
01149                              bindp->bind,
01150                              statement->err,
01151                              (dvoid *)bindp,
01152                              php_oci_bind_in_callback,
01153                              (dvoid *)bindp,
01154                              php_oci_bind_out_callback
01155                             )
01156               );
01157 
01158               if (statement->errcode != OCI_SUCCESS) {
01159                      statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
01160                      PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
01161                      return 1;
01162               }
01163        }
01164 
01165        if (type == SQLT_NTY) {
01166               /* Bind object */
01167               PHP_OCI_CALL_RETURN(statement->errcode, OCIBindObject,
01168                             (
01169                              bindp->bind,
01170                              statement->err,
01171                              bind_collection->tdo,
01172                              (dvoid **) &(bind_collection->collection),
01173                              (ub4 *) 0,
01174                              (dvoid **) 0,
01175                              (ub4 *) 0
01176                             )
01177               );
01178               
01179               if (statement->errcode) {
01180                      statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
01181                      PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
01182                      return 1;
01183               }
01184        }
01185        
01186        return 0;
01187 } /* }}} */
01188 
01189 /* {{{ php_oci_bind_in_callback()
01190  Callback used when binding LOBs and VARCHARs */
01191 sb4 php_oci_bind_in_callback(
01192                                    dvoid *ictxp,   /* context pointer */
01193                                    OCIBind *bindp,        /* bind handle */
01194                                    ub4 iter,              /* 0-based execute iteration value */
01195                                    ub4 index,             /* index of current array for PL/SQL or row index for SQL */
01196                                    dvoid **bufpp,         /* pointer to data */
01197                                    ub4 *alenp,            /* size after value/piece has been read */
01198                                    ub1 *piecep,    /* which piece */
01199                                    dvoid **indpp)         /* indicator value */
01200 {
01201        php_oci_bind *phpbind;
01202        zval *val;
01203        TSRMLS_FETCH();
01204 
01205        if (!(phpbind=(php_oci_bind *)ictxp) || !(val = phpbind->zval)) {
01206               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
01207               return OCI_ERROR;
01208        }
01209 
01210        if (ZVAL_IS_NULL(val)) {
01211               /* we're going to insert a NULL column */
01212               phpbind->indicator = -1;
01213               *bufpp = 0;
01214               *alenp = -1;
01215               *indpp = (dvoid *)&phpbind->indicator;
01216        } else if ((phpbind->descriptor == 0) && (phpbind->statement == 0)) {
01217               /* "normal string bind */
01218               convert_to_string(val);
01219 
01220               *bufpp = Z_STRVAL_P(val);
01221               *alenp = Z_STRLEN_P(val);
01222               *indpp = (dvoid *)&phpbind->indicator;
01223        } else if (phpbind->statement != 0) {
01224               /* RSET */
01225               *bufpp = phpbind->statement;
01226               *alenp = -1;         /* seems to be allright */
01227               *indpp = (dvoid *)&phpbind->indicator;
01228        } else {
01229               /* descriptor bind */
01230               *bufpp = phpbind->descriptor;
01231               *alenp = -1;         /* seems to be allright */
01232               *indpp = (dvoid *)&phpbind->indicator;
01233        }
01234 
01235        *piecep = OCI_ONE_PIECE; /* pass all data in one go */
01236 
01237        return OCI_CONTINUE;
01238 }/* }}} */
01239 
01240 /* {{{ php_oci_bind_out_callback()
01241  Callback used when binding LOBs and VARCHARs */
01242 sb4 php_oci_bind_out_callback(
01243                                    dvoid *octxp,    /* context pointer */
01244                                    OCIBind *bindp,         /* bind handle */
01245                                    ub4 iter,               /* 0-based execute iteration value */
01246                                    ub4 index,              /* index of current array for PL/SQL or row index for SQL */
01247                                    dvoid **bufpp,          /* pointer to data */
01248                                    ub4 **alenpp,    /* size after value/piece has been read */
01249                                    ub1 *piecep,     /* which piece */
01250                                    dvoid **indpp,          /* indicator value */
01251                                    ub2 **rcodepp)          /* return code */
01252 {
01253        php_oci_bind *phpbind;
01254        zval *val;
01255        sb4 retval = OCI_ERROR;
01256        TSRMLS_FETCH();
01257 
01258        if (!(phpbind=(php_oci_bind *)octxp) || !(val = phpbind->zval)) {
01259               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
01260               return retval;
01261        }
01262 
01263        if (Z_TYPE_P(val) == IS_RESOURCE) {
01264               /* Processing for ref-cursor out binds */
01265               if (phpbind->statement != NULL) {
01266                      *bufpp = phpbind->statement;
01267                      *alenpp = &phpbind->dummy_len;
01268                      *piecep = OCI_ONE_PIECE;
01269                      *rcodepp = &phpbind->retcode;
01270                      *indpp = &phpbind->indicator;
01271               }
01272               retval = OCI_CONTINUE;
01273        } else if (Z_TYPE_P(val) == IS_OBJECT) {
01274               zval **tmp;
01275               php_oci_descriptor *desc;
01276 
01277               if (!phpbind->descriptor) {
01278                      return OCI_ERROR;
01279               }
01280 
01281               /* Do not use the cached lob size if the descriptor is an
01282                * out-bind as the contents would have been changed for in/out
01283                * binds (Bug #46994).
01284                */
01285               if (zend_hash_find(Z_OBJPROP_P(val), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
01286                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find object outbind descriptor property");
01287                      return OCI_ERROR;
01288               }
01289               PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, desc);
01290               desc->lob_size = -1; /* force OCI8 to update cached size */
01291 
01292               *alenpp = &phpbind->dummy_len;
01293               *bufpp = phpbind->descriptor;
01294               *piecep = OCI_ONE_PIECE;
01295               *rcodepp = &phpbind->retcode;
01296               *indpp = &phpbind->indicator;
01297               retval = OCI_CONTINUE;
01298        } else {
01299               convert_to_string(val);
01300               zval_dtor(val);
01301               
01302               Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
01303               Z_STRVAL_P(val) = ecalloc(1, Z_STRLEN_P(phpbind->zval) + 1);
01304               
01305               /* XXX we assume that zend-zval len has 4 bytes */
01306               *alenpp = (ub4*) &Z_STRLEN_P(phpbind->zval);
01307               *bufpp = Z_STRVAL_P(phpbind->zval);
01308               *piecep = OCI_ONE_PIECE;
01309               *rcodepp = &phpbind->retcode;
01310               *indpp = &phpbind->indicator;
01311               retval = OCI_CONTINUE;
01312        }
01313 
01314        return retval;
01315 }
01316 /* }}} */
01317 
01318 /* {{{ php_oci_statement_get_column_helper()
01319  Helper function to get column by name and index */
01320 php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAMETERS, int need_data)
01321 {
01322        zval *z_statement, *column_index;
01323        php_oci_statement *statement;
01324        php_oci_out_column *column;
01325 
01326        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_statement, &column_index) == FAILURE) {
01327               return NULL;
01328        }
01329 
01330        statement = (php_oci_statement *) zend_fetch_resource(&z_statement TSRMLS_CC, -1, "oci8 statement", NULL, 1, le_statement);
01331 
01332        if (!statement) {
01333               return NULL;
01334        }
01335 
01336        if (need_data && !statement->has_data) {
01337               return NULL;
01338        }
01339        
01340        if (Z_TYPE_P(column_index) == IS_STRING) {
01341               column = php_oci_statement_get_column(statement, -1, Z_STRVAL_P(column_index), Z_STRLEN_P(column_index) TSRMLS_CC);
01342               if (!column) {
01343                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column name \"%s\"", Z_STRVAL_P(column_index));
01344                      return NULL;
01345               }
01346        } else {
01347               zval tmp;
01348               /* NB: for PHP4 compat only, it should be using 'Z' instead */
01349               tmp = *column_index;
01350               zval_copy_ctor(&tmp);
01351               convert_to_long(&tmp);
01352               column = php_oci_statement_get_column(statement, Z_LVAL(tmp), NULL, 0 TSRMLS_CC);
01353               if (!column) {
01354                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column index \"%ld\"", Z_LVAL(tmp));
01355                      zval_dtor(&tmp);
01356                      return NULL;
01357               }
01358               zval_dtor(&tmp);
01359        }
01360        return column;
01361 } /* }}} */
01362 
01363 /* {{{ php_oci_statement_get_type()
01364  Return type of the statement */
01365 int php_oci_statement_get_type(php_oci_statement *statement, ub2 *type TSRMLS_DC)
01366 {
01367        ub2 statement_type;
01368        
01369        *type = 0;
01370        
01371        PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement_type, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
01372 
01373        if (statement->errcode != OCI_SUCCESS) {
01374               statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
01375               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
01376               return 1;
01377        }
01378 
01379        *type = statement_type;
01380 
01381        return 0;
01382 } /* }}} */
01383 
01384 /* {{{ php_oci_statement_get_numrows()
01385  Get the number of rows fetched to the clientside (NOT the number of rows in the result set) */
01386 int php_oci_statement_get_numrows(php_oci_statement *statement, ub4 *numrows TSRMLS_DC)
01387 {
01388        ub4 statement_numrows;
01389        
01390        *numrows = 0;
01391        
01392        PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub4 *)&statement_numrows, (ub4 *)0, OCI_ATTR_ROW_COUNT, statement->err));
01393 
01394        if (statement->errcode != OCI_SUCCESS) {
01395               statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
01396               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
01397               return 1;
01398        }
01399 
01400        *numrows = statement_numrows;
01401 
01402        return 0;
01403 } /* }}} */
01404 
01405 /* {{{ php_oci_bind_array_by_name()
01406  Bind arrays to PL/SQL types */
01407 int php_oci_bind_array_by_name(php_oci_statement *statement, char *name, int name_len, zval* var, long max_table_length, long maxlength, long type TSRMLS_DC)
01408 {
01409        php_oci_bind *bind, *bindp;
01410 
01411        convert_to_array(var);
01412 
01413        if (maxlength < -1) {
01414               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid max length value (%ld)", maxlength);
01415               return 1;
01416        }
01417        
01418        switch(type) {
01419               case SQLT_NUM:
01420               case SQLT_INT:
01421               case SQLT_LNG:
01422                      bind = php_oci_bind_array_helper_number(var, max_table_length TSRMLS_CC);
01423                      break;
01424 
01425               case SQLT_FLT:
01426                      bind = php_oci_bind_array_helper_double(var, max_table_length TSRMLS_CC);
01427                      break;
01428                      
01429               case SQLT_AFC:
01430               case SQLT_CHR:
01431               case SQLT_VCS:
01432               case SQLT_AVC:
01433               case SQLT_STR:
01434               case SQLT_LVC:
01435                      if (maxlength == -1 && zend_hash_num_elements(Z_ARRVAL_P(var)) == 0) {
01436                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must provide max length value for empty arrays");
01437                             return 1;
01438                      }
01439                      bind = php_oci_bind_array_helper_string(var, max_table_length, maxlength TSRMLS_CC);
01440                      break;
01441               case SQLT_ODT:
01442                      bind = php_oci_bind_array_helper_date(var, max_table_length, statement->connection TSRMLS_CC);
01443                      break;
01444               default:
01445                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %ld", type);
01446                      return 1;
01447                      break;
01448        }
01449 
01450        if (bind == NULL) {
01451               /* failed to generate bind struct */
01452               return 1;
01453        }
01454        
01455        if (!statement->binds) {
01456               ALLOC_HASHTABLE(statement->binds);
01457               zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
01458        }
01459 
01460        zend_hash_update(statement->binds, name, name_len + 1, bind, sizeof(php_oci_bind), (void **)&bindp);
01461 
01462        bindp->descriptor = NULL;
01463        bindp->statement = NULL;
01464        bindp->parent_statement = statement;
01465        bindp->bind = NULL;
01466        bindp->zval = var;
01467        bindp->array.type = type;
01468        bindp->indicator = 0;              /* not used for array binds */
01469        bindp->type = 0;                   /* not used for array binds */
01470 
01471        zval_add_ref(&var);
01472 
01473        PHP_OCI_CALL_RETURN(statement->errcode,
01474                                                  OCIBindByName,
01475                                                  (
01476                                                         statement->stmt,
01477                                                         (OCIBind **)&bindp->bind,
01478                                                         statement->err,
01479                                                         (text *)name,
01480                                                         name_len,
01481                                                         (dvoid *) bindp->array.elements,
01482                                                         (sb4) bind->array.max_length,
01483                                                         (ub2)type,
01484                                                         (dvoid *)bindp->array.indicators,
01485                                                         (ub2 *)bind->array.element_lengths,
01486                                                         (ub2 *)0, /* bindp->array.retcodes, */
01487                                                         (ub4) max_table_length,
01488                                                         (ub4 *) &(bindp->array.current_length),
01489                                                         (ub4) OCI_DEFAULT
01490                                                  )
01491                                           );
01492        
01493               
01494        if (statement->errcode != OCI_SUCCESS) {
01495               efree(bind);
01496               statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
01497               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
01498               return 1;
01499        }
01500        efree(bind);
01501        return 0;
01502 } /* }}} */
01503 
01504 /* {{{ php_oci_bind_array_helper_string()
01505  Bind arrays to PL/SQL types */
01506 php_oci_bind *php_oci_bind_array_helper_string(zval* var, long max_table_length, long maxlength TSRMLS_DC)
01507 {
01508        php_oci_bind *bind;
01509        ub4 i;
01510        HashTable *hash;
01511        zval **entry;
01512 
01513        hash = HASH_OF(var);
01514 
01515        if (maxlength == -1) {
01516               zend_hash_internal_pointer_reset(hash);
01517               while (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE) {
01518                      convert_to_string_ex(entry);
01519                      if (Z_STRLEN_PP(entry) > maxlength) {
01520                             maxlength = Z_STRLEN_PP(entry) + 1;
01521                      }
01522                      zend_hash_move_forward(hash);
01523               }
01524        }
01525        
01526        bind = emalloc(sizeof(php_oci_bind));
01527        bind->array.elements        = (text *)safe_emalloc(max_table_length * (maxlength + 1), sizeof(text), 0);
01528        memset(bind->array.elements, 0, max_table_length * (maxlength + 1) * sizeof(text));
01529        bind->array.current_length  = zend_hash_num_elements(Z_ARRVAL_P(var));
01530        bind->array.old_length             = bind->array.current_length;
01531        bind->array.max_length             = maxlength;
01532        bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
01533        memset(bind->array.element_lengths, 0, max_table_length*sizeof(ub2));
01534        bind->array.indicators             = safe_emalloc(max_table_length, sizeof(sb2), 0);
01535        memset(bind->array.indicators, 0, max_table_length*sizeof(sb2));
01536        
01537        zend_hash_internal_pointer_reset(hash);
01538        
01539        for (i = 0; i < bind->array.current_length; i++) {
01540               if (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE) {
01541                      convert_to_string_ex(entry);
01542                      bind->array.element_lengths[i] = Z_STRLEN_PP(entry);
01543                      if (Z_STRLEN_PP(entry) == 0) {
01544                             bind->array.indicators[i] = -1;
01545                      }
01546                      zend_hash_move_forward(hash);
01547               } else {
01548                      break;
01549               }
01550        }
01551 
01552        zend_hash_internal_pointer_reset(hash);
01553        for (i = 0; i < max_table_length; i++) {
01554               if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
01555                      int element_length;
01556                      
01557                      convert_to_string_ex(entry);
01558                      element_length = (maxlength > Z_STRLEN_PP(entry)) ? Z_STRLEN_PP(entry) : maxlength;
01559                      
01560                      memcpy((text *)bind->array.elements + i*maxlength, Z_STRVAL_PP(entry), element_length);
01561                      ((text *)bind->array.elements)[i*maxlength + element_length] = '\0';
01562                      
01563                      zend_hash_move_forward(hash);
01564               } else {
01565                      ((text *)bind->array.elements)[i*maxlength] = '\0';
01566               }
01567        }
01568        zend_hash_internal_pointer_reset(hash);
01569 
01570        return bind;
01571 } /* }}} */
01572 
01573 /* {{{ php_oci_bind_array_helper_number()
01574  Bind arrays to PL/SQL types */
01575 php_oci_bind *php_oci_bind_array_helper_number(zval* var, long max_table_length TSRMLS_DC)
01576 {
01577        php_oci_bind *bind;
01578        ub4 i;
01579        HashTable *hash;
01580        zval **entry;
01581 
01582        hash = HASH_OF(var);
01583 
01584        bind = emalloc(sizeof(php_oci_bind));
01585        bind->array.elements        = (ub4 *)safe_emalloc(max_table_length, sizeof(ub4), 0);
01586        bind->array.current_length  = zend_hash_num_elements(Z_ARRVAL_P(var));
01587        bind->array.old_length             = bind->array.current_length;
01588        bind->array.max_length             = sizeof(ub4);
01589        bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
01590        memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
01591        bind->array.indicators             = NULL;
01592        
01593        zend_hash_internal_pointer_reset(hash);
01594        for (i = 0; i < max_table_length; i++) {
01595               if (i < bind->array.current_length) {
01596                      bind->array.element_lengths[i] = sizeof(ub4);
01597               }
01598               if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
01599                      convert_to_long_ex(entry);
01600                      ((ub4 *)bind->array.elements)[i] = (ub4) Z_LVAL_PP(entry);
01601                      zend_hash_move_forward(hash);
01602               } else {
01603                      ((ub4 *)bind->array.elements)[i] = 0;
01604               }
01605        }
01606        zend_hash_internal_pointer_reset(hash);
01607 
01608        return bind;
01609 } /* }}} */
01610 
01611 /* {{{ php_oci_bind_array_helper_double()
01612  Bind arrays to PL/SQL types */
01613 php_oci_bind *php_oci_bind_array_helper_double(zval* var, long max_table_length TSRMLS_DC)
01614 {
01615        php_oci_bind *bind;
01616        ub4 i;
01617        HashTable *hash;
01618        zval **entry;
01619 
01620        hash = HASH_OF(var);
01621 
01622        bind = emalloc(sizeof(php_oci_bind));
01623        bind->array.elements        = (double *)safe_emalloc(max_table_length, sizeof(double), 0);
01624        bind->array.current_length  = zend_hash_num_elements(Z_ARRVAL_P(var));
01625        bind->array.old_length             = bind->array.current_length;
01626        bind->array.max_length             = sizeof(double);
01627        bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
01628        memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
01629        bind->array.indicators             = NULL;
01630        
01631        zend_hash_internal_pointer_reset(hash);
01632        for (i = 0; i < max_table_length; i++) {
01633               if (i < bind->array.current_length) {
01634                      bind->array.element_lengths[i] = sizeof(double);
01635               }
01636               if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
01637                      convert_to_double_ex(entry);
01638                      ((double *)bind->array.elements)[i] = (double) Z_DVAL_PP(entry);
01639                      zend_hash_move_forward(hash);
01640               } else {
01641                      ((double *)bind->array.elements)[i] = 0;
01642               }
01643        }
01644        zend_hash_internal_pointer_reset(hash);
01645 
01646        return bind;
01647 } /* }}} */
01648 
01649 /* {{{ php_oci_bind_array_helper_date()
01650  Bind arrays to PL/SQL types */
01651 php_oci_bind *php_oci_bind_array_helper_date(zval* var, long max_table_length, php_oci_connection *connection TSRMLS_DC)
01652 {
01653        php_oci_bind *bind;
01654        ub4 i;
01655        HashTable *hash;
01656        zval **entry;
01657 
01658        hash = HASH_OF(var);
01659 
01660        bind = emalloc(sizeof(php_oci_bind));
01661        bind->array.elements        = (OCIDate *)safe_emalloc(max_table_length, sizeof(OCIDate), 0);
01662        bind->array.current_length  = zend_hash_num_elements(Z_ARRVAL_P(var));
01663        bind->array.old_length             = bind->array.current_length;
01664        bind->array.max_length             = sizeof(OCIDate);
01665        bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
01666        memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
01667        bind->array.indicators             = NULL;
01668 
01669        zend_hash_internal_pointer_reset(hash);
01670        for (i = 0; i < max_table_length; i++) {
01671               OCIDate oci_date;
01672               if (i < bind->array.current_length) {
01673                      bind->array.element_lengths[i] = sizeof(OCIDate);
01674               }
01675               if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
01676                      
01677                      convert_to_string_ex(entry);
01678                      PHP_OCI_CALL_RETURN(connection->errcode, OCIDateFromText, (connection->err, (CONST text *)Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), NULL, 0, NULL, 0, &oci_date));
01679 
01680                      if (connection->errcode != OCI_SUCCESS) {
01681                             /* failed to convert string to date */
01682                             efree(bind->array.element_lengths);
01683                             efree(bind->array.elements);
01684                             efree(bind);
01685                             connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
01686                             PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
01687                             return NULL;
01688                      }
01689                      
01690                      ((OCIDate *)bind->array.elements)[i] = oci_date;
01691                      zend_hash_move_forward(hash);
01692               } else {
01693                      PHP_OCI_CALL_RETURN(connection->errcode, OCIDateFromText, (connection->err, (CONST text *)"01-JAN-00", sizeof("01-JAN-00")-1, NULL, 0, NULL, 0, &oci_date));
01694 
01695                      if (connection->errcode != OCI_SUCCESS) {
01696                             /* failed to convert string to date */
01697                             efree(bind->array.element_lengths);
01698                             efree(bind->array.elements);
01699                             efree(bind);
01700                             connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
01701                             PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
01702                             return NULL;
01703                      }
01704        
01705                      ((OCIDate *)bind->array.elements)[i] = oci_date;
01706               }
01707        }
01708        zend_hash_internal_pointer_reset(hash);
01709 
01710        return bind;
01711 } /* }}} */
01712 
01713 #endif /* HAVE_OCI8 */
01714 
01715 /*
01716  * Local variables:
01717  * tab-width: 4
01718  * c-basic-offset: 4
01719  * End:
01720  * vim600: noet sw=4 ts=4 fdm=marker
01721  * vim<600: noet sw=4 ts=4
01722  */