root/ext/oci8/oci8_statement.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_oci_statement_create
  2. php_oci_get_implicit_resultset
  3. php_oci_statement_set_prefetch
  4. php_oci_cleanup_pre_fetch
  5. php_oci_statement_fetch
  6. php_oci_statement_get_column
  7. php_oci_define_callback
  8. php_oci_statement_execute
  9. php_oci_statement_cancel
  10. php_oci_statement_free
  11. php_oci_bind_pre_exec
  12. php_oci_bind_post_exec
  13. php_oci_bind_by_name
  14. php_oci_bind_in_callback
  15. php_oci_bind_out_callback
  16. php_oci_statement_get_column_helper
  17. php_oci_statement_get_type
  18. php_oci_statement_get_numrows
  19. php_oci_bind_array_by_name
  20. php_oci_bind_array_helper_string
  21. php_oci_bind_array_helper_number
  22. php_oci_bind_array_helper_double
  23. php_oci_bind_array_helper_date

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Stig Sæther Bakken <ssb@php.net>                            |
  16    |          Thies C. Arntzen <thies@thieso.net>                         |
  17    |                                                                      |
  18    | Collection support by Andy Sautins <asautins@veripost.net>           |
  19    | Temporary LOB support by David Benson <dbenson@mancala.com>          |
  20    | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at>        |
  21    |                                                                      |
  22    | Redesigned by: Antony Dovgal <antony@zend.com>                       |
  23    |                Andi Gutmans <andi@zend.com>                          |
  24    |                Wez Furlong <wez@omniti.com>                          |
  25    +----------------------------------------------------------------------+
  26 */
  27 
  28 /* $Id$ */
  29 
  30 
  31 #ifdef HAVE_CONFIG_H
  32 #include "config.h"
  33 #endif
  34 
  35 #include "php.h"
  36 #include "ext/standard/info.h"
  37 #include "php_ini.h"
  38 
  39 #if HAVE_OCI8
  40 
  41 #include "php_oci8.h"
  42 #include "php_oci8_int.h"
  43 
  44 /* {{{ php_oci_statement_create()
  45  Create statemend handle and allocate necessary resources */
  46 php_oci_statement *php_oci_statement_create(php_oci_connection *connection, char *query, int query_len)
  47 {
  48         php_oci_statement *statement;
  49         sword errstatus;
  50 
  51         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  52 
  53         statement = ecalloc(1,sizeof(php_oci_statement));
  54 
  55         if (!query_len) {
  56                 /* do not allocate stmt handle for refcursors, we'll get it from OCIStmtPrepare2() */
  57                 PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->stmt), OCI_HTYPE_STMT, 0, NULL));
  58         }
  59                 
  60         PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->err), OCI_HTYPE_ERROR, 0, NULL));
  61         
  62         if (query_len > 0) {
  63                 PHP_OCI_CALL_RETURN(errstatus, OCIStmtPrepare2,
  64                                 (
  65                                  connection->svc,
  66                                  &(statement->stmt),
  67                                  connection->err,
  68                                  (text *)query,
  69                                  query_len,
  70                                  NULL,
  71                                  0,
  72                                  OCI_NTV_SYNTAX,
  73                                  OCI_DEFAULT
  74                                 )
  75                 );
  76 #ifdef HAVE_OCI8_DTRACE
  77                 if (DTRACE_OCI8_SQLTEXT_ENABLED()) {
  78                         DTRACE_OCI8_SQLTEXT(connection, connection->client_id, statement, query);
  79                 }
  80 #endif /* HAVE_OCI8_DTRACE */
  81 
  82                 if (errstatus != OCI_SUCCESS) {
  83                         connection->errcode = php_oci_error(connection->err, errstatus);
  84 
  85                         PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, OCI_STRLS_CACHE_DELETE));
  86                         PHP_OCI_CALL(OCIHandleFree,(statement->err, OCI_HTYPE_ERROR));
  87                         PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  88                         efree(statement);
  89                         return NULL;
  90                 }
  91         }
  92         
  93         if (query && query_len) {
  94                 statement->last_query = ecalloc(1, query_len + 1);
  95                 memcpy(statement->last_query, query, query_len);
  96                 statement->last_query_len = query_len;
  97         }
  98         else {
  99                 statement->last_query = NULL;
 100                 statement->last_query_len = 0;
 101         }
 102 
 103         statement->connection = connection;
 104         statement->has_data = 0;
 105         statement->has_descr = 0;
 106         statement->parent_stmtid = 0;
 107         statement->impres_child_stmt = NULL;
 108         statement->impres_count = 0;
 109         statement->impres_flag = PHP_OCI_IMPRES_UNKNOWN;  /* may or may not have Implicit Result Set children */
 110         ++GC_REFCOUNT(statement->connection->id);
 111 
 112         if (OCI_G(default_prefetch) >= 0) {
 113                 php_oci_statement_set_prefetch(statement, (ub4)OCI_G(default_prefetch));
 114         } else {
 115                 php_oci_statement_set_prefetch(statement, (ub4)100); /* semi-arbitrary, "sensible default" */
 116         }
 117         
 118         PHP_OCI_REGISTER_RESOURCE(statement, le_statement);
 119 
 120         OCI_G(num_statements)++;
 121         
 122         return statement;
 123 }
 124 /* }}} */
 125 
 126 /* {{{ php_oci_get_implicit_resultset()
 127    Fetch implicit result set statement resource */
 128 php_oci_statement *php_oci_get_implicit_resultset(php_oci_statement *statement)
 129 {
 130 #if (OCI_MAJOR_VERSION < 12)
 131         php_error_docref(NULL, E_WARNING, "Implicit results are available in Oracle Database 12c onwards");
 132         return NULL;
 133 #else
 134         void *result;
 135         ub4   rtype;
 136         php_oci_statement *statement2;  /* implicit result set statement handle */
 137         sword errstatus;
 138 
 139         PHP_OCI_CALL_RETURN(errstatus, OCIStmtGetNextResult, (statement->stmt, statement->err, &result, &rtype, OCI_DEFAULT));
 140         if (errstatus == OCI_NO_DATA) {
 141                 return NULL;
 142         }
 143 
 144         if (rtype != OCI_RESULT_TYPE_SELECT) {
 145                 /* Only OCI_RESULT_TYPE_SELECT is supported by Oracle DB 12cR1 */
 146                 php_error_docref(NULL, E_WARNING, "Unexpected implicit result type returned from Oracle Database");
 147                 return NULL;
 148         } else {
 149                 statement2 = ecalloc(1,sizeof(php_oci_statement));
 150 
 151                 PHP_OCI_CALL(OCIHandleAlloc, (statement->connection->env, (dvoid **)&(statement2->err), OCI_HTYPE_ERROR, 0, NULL));
 152                 statement2->stmt = (OCIStmt *)result;   
 153                 statement2->parent_stmtid = statement->id;
 154                 statement2->impres_child_stmt = NULL;
 155                 statement2->impres_count = 0;
 156                 statement2->impres_flag = PHP_OCI_IMPRES_IS_CHILD;
 157                 statement2->connection = statement->connection;
 158                 statement2->errcode = 0;
 159                 statement2->last_query = NULL;
 160                 statement2->last_query_len = 0;
 161                 statement2->columns = NULL;
 162                 statement2->binds = NULL;
 163                 statement2->defines = NULL;
 164                 statement2->ncolumns = 0;
 165                 statement2->executed = 0;
 166                 statement2->has_data = 0;
 167                 statement2->has_descr = 0;
 168                 statement2->stmttype = 0;
 169 
 170                 GC_REFCOUNT(statement->id)++;
 171                 GC_REFCOUNT(statement2->connection->id)++;
 172 
 173                 php_oci_statement_set_prefetch(statement2, statement->prefetch_count);
 174                 
 175                 PHP_OCI_REGISTER_RESOURCE(statement2, le_statement);
 176         
 177                 OCI_G(num_statements)++;
 178                 
 179                 return statement2;
 180         }
 181 #endif /* OCI_MAJOR_VERSION < 12 */
 182 }
 183 /* }}} */
 184 
 185 /* {{{ php_oci_statement_set_prefetch()
 186  Set prefetch buffer size for the statement */
 187 int php_oci_statement_set_prefetch(php_oci_statement *statement, ub4 prefetch )
 188 {
 189         sword errstatus;
 190 
 191         if (prefetch > 20000) {
 192                 prefetch = 20000;               /* keep it somewhat sane */
 193         }
 194 
 195         PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (statement->stmt, OCI_HTYPE_STMT, &prefetch, 0, OCI_ATTR_PREFETCH_ROWS, statement->err));
 196         
 197         if (errstatus != OCI_SUCCESS) {
 198                 statement->errcode = php_oci_error(statement->err, errstatus);
 199                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 200                 statement->prefetch_count = 0;
 201                 return 1;
 202         }
 203         statement->prefetch_count = prefetch;
 204         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 205         return 0;
 206 }
 207 /* }}} */
 208 
 209 /* {{{ php_oci_cleanup_pre_fetch()
 210    Helper function to cleanup ref-cursors and descriptors from the previous row */
 211 int php_oci_cleanup_pre_fetch(zval *data)
 212 {
 213         php_oci_out_column *outcol = (php_oci_out_column*) Z_PTR_P(data);
 214 
 215         if (!outcol->is_descr && !outcol->is_cursor)
 216                 return ZEND_HASH_APPLY_KEEP;
 217 
 218         switch(outcol->data_type) {
 219                 case SQLT_CLOB:
 220                 case SQLT_BLOB:
 221                 case SQLT_RDD:
 222                 case SQLT_BFILE:
 223                         if (outcol->descid) {
 224                                 zend_list_delete(outcol->descid);
 225                                 outcol->descid = 0;
 226                         }
 227                         break;
 228                 case SQLT_RSET:
 229                         if (outcol->stmtid) {
 230                                 zend_list_delete(outcol->stmtid);
 231                                 outcol->stmtid = 0;
 232                                 outcol->nested_statement = NULL;
 233                         }
 234                         break;
 235                 default:
 236                         break;
 237         }
 238         return ZEND_HASH_APPLY_KEEP;
 239 
 240 }
 241 /* }}} */
 242 
 243 /* {{{ php_oci_statement_fetch()
 244  Fetch a row from the statement */
 245 int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows)
 246 {
 247         int i;
 248         void *handlepp;
 249         ub4 typep, iterp, idxp;
 250         ub1 in_outp, piecep;
 251         zend_bool piecewisecols = 0;
 252         php_oci_out_column *column;
 253         sword errstatus;
 254 
 255         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 256 
 257         if (statement->has_descr && statement->columns) {
 258                 zend_hash_apply(statement->columns, php_oci_cleanup_pre_fetch);
 259     }
 260 
 261         PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
 262 
 263         if (errstatus == OCI_NO_DATA || nrows == 0) {
 264                 if (statement->last_query == NULL) {
 265                         /* reset define-list for refcursors */
 266                         if (statement->columns) {
 267                                 zend_hash_destroy(statement->columns);
 268                                 efree(statement->columns);
 269                                 statement->columns = NULL;
 270                                 statement->ncolumns = 0;
 271                         }
 272                         statement->executed = 0;
 273                 }
 274 
 275                 statement->has_data = 0;
 276 
 277                 if (nrows == 0) {
 278                         /* this is exactly what we requested */
 279                         return 0;
 280                 }
 281                 return 1;
 282         }
 283 
 284         /* reset length for all piecewise columns */
 285         for (i = 0; i < statement->ncolumns; i++) {
 286                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
 287                 if (column && column->piecewise) {
 288                         column->retlen4 = 0;
 289                         piecewisecols = 1;
 290                 }
 291         }
 292         
 293         while (errstatus == OCI_NEED_DATA) {
 294                 if (piecewisecols) {
 295                         PHP_OCI_CALL_RETURN(errstatus,
 296                                 OCIStmtGetPieceInfo,
 297                                    (
 298                                         statement->stmt,
 299                                         statement->err,
 300                                         &handlepp,
 301                                         &typep,
 302                                         &in_outp,
 303                                         &iterp,
 304                                         &idxp,
 305                                         &piecep
 306                                    )
 307                         );
 308 
 309                         /* scan through our columns for a piecewise column with a matching handle */
 310                         for (i = 0; i < statement->ncolumns; i++) {
 311                                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
 312                                 if (column && column->piecewise && handlepp == column->oci_define)   {
 313                                         if (!column->data) {
 314                                                 column->data = (text *) ecalloc(1, PHP_OCI_PIECE_SIZE + 1);
 315                                         } else {
 316                                                 column->data = erealloc(column->data, column->retlen4 + PHP_OCI_PIECE_SIZE + 1);
 317                                         }
 318                                         column->cb_retlen = PHP_OCI_PIECE_SIZE;
 319 
 320                                         /* and instruct fetch to fetch waiting piece into our buffer */
 321                                         PHP_OCI_CALL(OCIStmtSetPieceInfo,
 322                                                    (
 323                                                         (void *) column->oci_define,
 324                                                         OCI_HTYPE_DEFINE,
 325                                                         statement->err,
 326                                                         ((char*)column->data) + column->retlen4,
 327                                                         &(column->cb_retlen),
 328                                                         piecep,
 329                                                         &column->indicator,
 330                                                         &column->retcode
 331                                                    )
 332                                         );
 333                                 }
 334                         }
 335                 }
 336 
 337                 PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
 338 
 339                 if (piecewisecols) {
 340                         for (i = 0; i < statement->ncolumns; i++) {
 341                                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
 342                                 if (column && column->piecewise && handlepp == column->oci_define)      {
 343                                         column->retlen4 += column->cb_retlen;
 344                                 }
 345                         }
 346                 }
 347         }
 348 
 349         if (errstatus == OCI_SUCCESS_WITH_INFO || errstatus == OCI_SUCCESS) {
 350                 statement->has_data = 1;
 351 
 352                 /* do the stuff needed for OCIDefineByName */
 353                 for (i = 0; i < statement->ncolumns; i++) {
 354                         column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
 355                         if (column == NULL) {
 356                                 continue;
 357                         }
 358                         
 359                         if (!column->define) {
 360                                 continue;
 361                         }
 362                         
 363                         zval_dtor(column->define->zval);
 364                         php_oci_column_to_zval(column, column->define->zval, 0);
 365                 }
 366 
 367                 return 0;
 368         }
 369 
 370         statement->errcode = php_oci_error(statement->err, errstatus);
 371         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 372 
 373         statement->has_data = 0;
 374 
 375         return 1;
 376 }
 377 /* }}} */
 378 
 379 /* {{{ php_oci_statement_get_column()
 380  Get column from the result set */
 381 php_oci_out_column *php_oci_statement_get_column(php_oci_statement *statement, zend_long column_index, char *column_name, int column_name_len)
 382 {
 383         php_oci_out_column *column = NULL;
 384         int i;
 385 
 386         if (statement->columns == NULL) { /* we release the columns at the end of a fetch */
 387                 return NULL;
 388         }
 389 
 390         if (column_name) {
 391                 for (i = 0; i < statement->ncolumns; i++) {
 392                         column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
 393                         if (column == NULL) {
 394                                 continue;
 395                         } else if (((int) column->name_len == column_name_len) && (!strncmp(column->name, column_name, column_name_len))) {
 396                                 return column;
 397                         }
 398                 }
 399         } else if (column_index != -1) {
 400                 if ((column = zend_hash_index_find_ptr(statement->columns, column_index)) == NULL) {
 401                         return NULL;
 402                 }
 403                 return column;
 404         }
 405 
 406         return NULL;
 407 }
 408 /* }}} */
 409 
 410 /* {{{ php_oci_define_callback() */
 411 sb4 php_oci_define_callback(dvoid *ctx, OCIDefine *define, ub4 iter, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
 412 {
 413         php_oci_out_column *outcol = (php_oci_out_column *)ctx;
 414 
 415         if (!outcol) {
 416                 
 417                 php_error_docref(NULL, E_WARNING, "Invalid context pointer value");
 418                 return OCI_ERROR;
 419         }
 420         
 421         switch(outcol->data_type) {
 422                 case SQLT_RSET: {
 423                                 php_oci_statement *nested_stmt;
 424 
 425                                 nested_stmt = php_oci_statement_create(outcol->statement->connection, NULL, 0);
 426                                 if (!nested_stmt) {
 427                                         return OCI_ERROR;
 428                                 }
 429                                 nested_stmt->parent_stmtid = outcol->statement->id;
 430                                 ++GC_REFCOUNT(outcol->statement->id);
 431                                 outcol->nested_statement = nested_stmt;
 432                                 outcol->stmtid = nested_stmt->id;
 433 
 434                                 *bufpp = nested_stmt->stmt;
 435                                 *alenpp = &(outcol->retlen4);
 436                                 *piecep = OCI_ONE_PIECE;
 437                                 *indpp = &(outcol->indicator);
 438                                 *rcpp = &(outcol->retcode);
 439                                 return OCI_CONTINUE;
 440                         }
 441                         break;
 442                 case SQLT_RDD:
 443                 case SQLT_BLOB:
 444                 case SQLT_CLOB:
 445                 case SQLT_BFILE: {
 446                                 php_oci_descriptor *descr;
 447                                 int dtype;
 448 
 449                                 if (outcol->data_type == SQLT_BFILE) {
 450                                         dtype = OCI_DTYPE_FILE;
 451                                 } else if (outcol->data_type == SQLT_RDD ) {
 452                                         dtype = OCI_DTYPE_ROWID;
 453                                 } else {
 454                                         dtype = OCI_DTYPE_LOB;
 455                                 }
 456 
 457                                 descr = php_oci_lob_create(outcol->statement->connection, dtype);
 458                                 if (!descr) {
 459                                         return OCI_ERROR;
 460                                 }
 461                                 outcol->descid = descr->id;
 462                                 descr->charset_form = outcol->charset_form;
 463                                 
 464                                 *bufpp = descr->descriptor;
 465                                 *alenpp = &(outcol->retlen4);
 466                                 *piecep = OCI_ONE_PIECE;
 467                                 *indpp = &(outcol->indicator);
 468                                 *rcpp = &(outcol->retcode);
 469 
 470                                 return OCI_CONTINUE;
 471                         }
 472                         break;
 473         }
 474         return OCI_ERROR;
 475 }
 476 /* }}} */
 477 
 478 /* {{{ php_oci_statement_execute()
 479  Execute statement */
 480 int php_oci_statement_execute(php_oci_statement *statement, ub4 mode)
 481 {
 482         php_oci_out_column *outcol;
 483         OCIParam *param = NULL;
 484         text *colname;
 485         ub4 counter;
 486         ub2 define_type;
 487         ub4 iters;
 488         ub4 colcount;
 489         ub2 dynamic;
 490         dvoid *buf;
 491         sword errstatus;
 492 
 493         switch (mode) {
 494                 case OCI_COMMIT_ON_SUCCESS:
 495                 case OCI_DESCRIBE_ONLY:
 496                 case OCI_DEFAULT:
 497                         /* only these are allowed */
 498 #ifdef HAVE_OCI8_DTRACE
 499                         if (DTRACE_OCI8_EXECUTE_MODE_ENABLED()) {
 500                                 DTRACE_OCI8_EXECUTE_MODE(statement->connection, statement->connection->client_id, statement, mode);
 501                         }
 502 #endif /* HAVE_OCI8_DTRACE */
 503                         break;
 504                 default:
 505                         php_error_docref(NULL, E_WARNING, "Invalid execute mode given: %d", mode);
 506                         return 1;
 507                         break;
 508         }
 509         
 510         if (!statement->stmttype) {
 511                 /* get statement type */
 512                 PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement->stmttype, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
 513 
 514                 if (errstatus != OCI_SUCCESS) {
 515                         statement->errcode = php_oci_error(statement->err, errstatus);
 516                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 517                         return 1;
 518                 } else {
 519                         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 520                 }
 521         }
 522 
 523         if (statement->stmttype == OCI_STMT_SELECT) {
 524                 iters = 0;
 525         } else {
 526                 iters = 1;
 527         }
 528         
 529         if (statement->last_query) { /* Don't execute REFCURSORS or Implicit Result Set handles */
 530 
 531                 if (statement->binds) {
 532                         int result = 0;
 533                         zend_hash_apply_with_argument(statement->binds, php_oci_bind_pre_exec, (void *)&result);
 534                         if (result) {
 535                                 return 1;
 536                         }
 537                 }
 538 
 539                 /* execute statement */
 540                 PHP_OCI_CALL_RETURN(errstatus, OCIStmtExecute, (statement->connection->svc, statement->stmt, statement->err, iters, 0, NULL, NULL, mode));
 541 
 542                 if (errstatus != OCI_SUCCESS) {
 543                         statement->errcode = php_oci_error(statement->err, errstatus);
 544                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 545                         return 1;
 546                 }
 547                 
 548                 if (statement->binds) {
 549                         zend_hash_apply(statement->binds, php_oci_bind_post_exec);
 550                 }
 551 
 552                 if (mode & OCI_COMMIT_ON_SUCCESS) {
 553                         /* No need to rollback on disconnect */
 554                         statement->connection->rb_on_disconnect = 0;
 555                 } else if (statement->stmttype != OCI_STMT_SELECT) {
 556                         /* Assume some uncommitted DML occurred */
 557                         statement->connection->rb_on_disconnect = 1;
 558                 }
 559                 /* else for SELECT with OCI_NO_AUTO_COMMIT, leave
 560                  * "rb_on_disconnect" at its previous value.  SELECT can't
 561                  * initiate uncommitted DML. (An AUTONOMOUS_TRANSACTION in
 562                  * invoked PL/SQL must explicitly rollback/commit else the
 563                  * SELECT fails).
 564                  */
 565 
 566                 statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 567         }
 568 
 569         if (statement->stmttype == OCI_STMT_SELECT && statement->executed == 0) {
 570                 /* we only need to do the define step is this very statement is executed the first time! */
 571                 statement->executed = 1;
 572                 
 573                 ALLOC_HASHTABLE(statement->columns);
 574                 zend_hash_init(statement->columns, 13, NULL, php_oci_column_hash_dtor, 0);
 575                 
 576                 counter = 1;
 577 
 578                 /* get number of columns */
 579                 PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *)&colcount, (ub4 *)0, OCI_ATTR_PARAM_COUNT, statement->err));
 580                 
 581                 if (errstatus != OCI_SUCCESS) {
 582                         statement->errcode = php_oci_error(statement->err, errstatus);
 583                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 584                         return 1;
 585                 }
 586 
 587                 statement->ncolumns = colcount;
 588                 
 589                 for (counter = 1; counter <= colcount; counter++) {
 590                         outcol = (php_oci_out_column *) ecalloc(1, sizeof(php_oci_out_column));
 591                         
 592                         if ((outcol = zend_hash_index_update_ptr(statement->columns, counter, outcol)) == NULL) {
 593                                 FREE_HASHTABLE(statement->columns);
 594                                 /* out of memory */
 595                                 return 1;
 596                         }
 597                         
 598                         /* get column */
 599                         PHP_OCI_CALL_RETURN(errstatus, OCIParamGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, statement->err, (dvoid**)&param, counter));
 600                         
 601                         if (errstatus != OCI_SUCCESS) {
 602                                 statement->errcode = php_oci_error(statement->err, errstatus);
 603                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 604                                 return 1;
 605                         }
 606 
 607                         /* get column datatype */
 608                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_type, (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->err));
 609 
 610                         if (errstatus != OCI_SUCCESS) {
 611                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 612                                 statement->errcode = php_oci_error(statement->err, errstatus);
 613                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 614                                 return 1;
 615                         }
 616 
 617                         /* get character set form  */
 618                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_form, (ub4 *)0, OCI_ATTR_CHARSET_FORM, statement->err));
 619 
 620                         if (errstatus != OCI_SUCCESS) {
 621                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 622                                 statement->errcode = php_oci_error(statement->err, errstatus);
 623                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 624                                 return 1;
 625                         }
 626         
 627                         /* get character set id  */
 628                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_id, (ub4 *)0, OCI_ATTR_CHARSET_ID, statement->err));
 629 
 630                         if (errstatus != OCI_SUCCESS) {
 631                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 632                                 statement->errcode = php_oci_error(statement->err, errstatus);
 633                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 634                                 return 1;
 635                         }
 636         
 637                         /* get size of the column */
 638                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_size, (dvoid *)0, OCI_ATTR_DATA_SIZE, statement->err));
 639                         
 640                         if (errstatus != OCI_SUCCESS) {
 641                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 642                                 statement->errcode = php_oci_error(statement->err, errstatus);
 643                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 644                                 return 1;
 645                         }
 646 
 647                         outcol->storage_size4 = outcol->data_size;
 648                         outcol->retlen = outcol->data_size;
 649 
 650                         /* get scale of the column */
 651                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->scale, (dvoid *)0, OCI_ATTR_SCALE, statement->err));
 652                         
 653                         if (errstatus != OCI_SUCCESS) {
 654                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 655                                 statement->errcode = php_oci_error(statement->err, errstatus);
 656                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 657                                 return 1;
 658                         }
 659 
 660                         /* get precision of the column */
 661                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->precision, (dvoid *)0, OCI_ATTR_PRECISION, statement->err));
 662                         
 663                         if (errstatus != OCI_SUCCESS) {
 664                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 665                                 statement->errcode = php_oci_error(statement->err, errstatus);
 666                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 667                                 return 1;
 668                         }
 669                         
 670                         /* get name of the column */
 671                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid **)&colname, (ub4 *)&outcol->name_len, (ub4)OCI_ATTR_NAME, statement->err));
 672                         
 673                         if (errstatus != OCI_SUCCESS) {
 674                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 675                                 statement->errcode = php_oci_error(statement->err, errstatus);
 676                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 677                                 return 1;
 678                         }
 679                         PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 680 
 681                         outcol->name = ecalloc(1, outcol->name_len + 1);
 682                         memcpy(outcol->name, colname, outcol->name_len);
 683 
 684                         /* find a user-set define */
 685                         if (statement->defines) {
 686                                 if ((outcol->define = zend_hash_str_find_ptr(statement->defines, outcol->name, outcol->name_len)) != NULL) {
 687                                         if (outcol->define->type) {
 688                                                 outcol->data_type = outcol->define->type;
 689                                         }
 690                                 }
 691                         }
 692 
 693                         buf = 0;
 694                         switch (outcol->data_type) {
 695                                 case SQLT_RSET:
 696                                         outcol->statement = statement; /* parent handle */
 697 
 698                                         define_type = SQLT_RSET;
 699                                         outcol->is_cursor = 1;
 700                                         outcol->statement->has_descr = 1;
 701                                         outcol->storage_size4 = -1;
 702                                         outcol->retlen = -1;
 703                                         dynamic = OCI_DYNAMIC_FETCH;
 704                                         break;
 705 
 706                                 case SQLT_RDD:   /* ROWID */
 707                                 case SQLT_BLOB:  /* binary LOB */
 708                                 case SQLT_CLOB:  /* character LOB */
 709                                 case SQLT_BFILE: /* binary file LOB */
 710                                         outcol->statement = statement; /* parent handle */
 711 
 712                                         define_type = outcol->data_type;
 713                                         outcol->is_descr = 1;
 714                                         outcol->statement->has_descr = 1;
 715                                         outcol->storage_size4 = -1;
 716                                         outcol->chunk_size = 0;
 717                                         dynamic = OCI_DYNAMIC_FETCH;
 718                                         break;
 719 
 720                                 case SQLT_LNG:
 721                                 case SQLT_LBI:
 722                                         if (outcol->data_type == SQLT_LBI) {
 723                                                 define_type = SQLT_BIN;
 724                                         } else {
 725                                                 define_type = SQLT_CHR;
 726                                         }
 727                                         outcol->storage_size4 = PHP_OCI_MAX_DATA_SIZE;
 728                                         outcol->piecewise = 1;
 729                                         dynamic = OCI_DYNAMIC_FETCH;
 730                                         break;
 731 
 732                                 case SQLT_BIN:
 733                                 default:
 734                                         define_type = SQLT_CHR;
 735                                         if (outcol->data_type == SQLT_BIN) {
 736                                                 define_type = SQLT_BIN;
 737                                         }
 738                                         if ((outcol->data_type == SQLT_DAT) || (outcol->data_type == SQLT_NUM)
 739 #ifdef SQLT_TIMESTAMP
 740                                                 || (outcol->data_type == SQLT_TIMESTAMP)
 741 #endif
 742 #ifdef SQLT_TIMESTAMP_TZ
 743                                                 || (outcol->data_type == SQLT_TIMESTAMP_TZ)
 744 #endif
 745 #ifdef SQLT_TIMESTAMP_LTZ
 746                                                 || (outcol->data_type == SQLT_TIMESTAMP_LTZ)
 747 #endif
 748 #ifdef SQLT_INTERVAL_YM
 749                                                 || (outcol->data_type == SQLT_INTERVAL_YM)
 750 #endif
 751 #ifdef SQLT_INTERVAL_DS
 752                                                 || (outcol->data_type == SQLT_INTERVAL_DS)
 753 #endif
 754                                                 ) {
 755                                                 outcol->storage_size4 = 512; /* XXX this should fit "most" NLS date-formats and Numbers */
 756 #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
 757                                         } else if (outcol->data_type == SQLT_IBFLOAT || outcol->data_type == SQLT_IBDOUBLE) {
 758                                                 outcol->storage_size4 = 1024;
 759 #endif
 760                                         } else {
 761                                                 outcol->storage_size4++; /* add one for string terminator */
 762                                         }
 763                                         
 764                                         outcol->storage_size4 *= 3;
 765                                         
 766                                         dynamic = OCI_DEFAULT;
 767                                         buf = outcol->data = (text *) safe_emalloc(1, outcol->storage_size4, 0);
 768                                         memset(buf, 0, outcol->storage_size4);
 769                                         break;
 770                         }
 771 
 772                         if (dynamic == OCI_DYNAMIC_FETCH) {
 773                                 PHP_OCI_CALL_RETURN(errstatus,
 774                                         OCIDefineByPos,
 775                                         (
 776                                                 statement->stmt,                                                        /* IN/OUT handle to the requested SQL query */
 777                                                 (OCIDefine **)&outcol->oci_define,                      /* IN/OUT pointer to a pointer to a define handle */
 778                                                 statement->err,                                                         /* IN/OUT An error handle  */
 779                                                 counter,                                                                        /* IN     position in the select list */
 780                                                 (dvoid *)NULL,                                                          /* IN/OUT pointer to a buffer */
 781                                                 outcol->storage_size4,                                          /* IN     The size of each valuep buffer in bytes */
 782                                                 define_type,                                                            /* IN     The data type */
 783                                                 (dvoid *)&outcol->indicator,                            /* IN     pointer to an indicator variable or arr */
 784                                                 (ub2 *)NULL,                                                            /* IN/OUT Pointer to array of length of data fetched */
 785                                                 (ub2 *)NULL,                                                            /* OUT    Pointer to array of column-level return codes */
 786                                                 OCI_DYNAMIC_FETCH                                                       /* IN     mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
 787                                         )
 788                                 );
 789 
 790                         } else {
 791                                 PHP_OCI_CALL_RETURN(errstatus,
 792                                         OCIDefineByPos,
 793                                         (
 794                                                 statement->stmt,                                                        /* IN/OUT handle to the requested SQL query */
 795                                                 (OCIDefine **)&outcol->oci_define,                      /* IN/OUT pointer to a pointer to a define handle */
 796                                                 statement->err,                                                         /* IN/OUT An error handle  */
 797                                                 counter,                                                                        /* IN     position in the select list */
 798                                                 (dvoid *)buf,                                                           /* IN/OUT pointer to a buffer */
 799                                                 outcol->storage_size4,                                          /* IN     The size of each valuep buffer in bytes */
 800                                                 define_type,                                                            /* IN     The data type */
 801                                                 (dvoid *)&outcol->indicator,                            /* IN     pointer to an indicator variable or arr */
 802                                                 (ub2 *)&outcol->retlen,                                         /* IN/OUT Pointer to array of length of data fetched */
 803                                                 (ub2 *)&outcol->retcode,                                        /* OUT    Pointer to array of column-level return codes */
 804                                                 OCI_DEFAULT                                                                     /* IN     mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
 805                                         )
 806                                 );
 807 
 808                         }
 809                         
 810                         if (errstatus != OCI_SUCCESS) {
 811                                 statement->errcode = php_oci_error(statement->err, errstatus);
 812                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 813                                 return 1;
 814                         }
 815 
 816                         /* additional OCIDefineDynamic() call */
 817                         switch (outcol->data_type) {
 818                                 case SQLT_RSET:
 819                                 case SQLT_RDD:
 820                                 case SQLT_BLOB:
 821                                 case SQLT_CLOB:
 822                                 case SQLT_BFILE:
 823                                         PHP_OCI_CALL_RETURN(errstatus,
 824                                                 OCIDefineDynamic,
 825                                                 (
 826                                                         outcol->oci_define,
 827                                                         statement->err,
 828                                                         (dvoid *)outcol,
 829                                                         php_oci_define_callback
 830                                                 )
 831                                         );
 832 
 833                                         if (errstatus != OCI_SUCCESS) {
 834                                                 statement->errcode = php_oci_error(statement->err, errstatus);
 835                                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 836                                                 return 1;
 837                                         }
 838                                         break;
 839                         }
 840                 }
 841                 statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 842         }
 843 
 844         return 0;
 845 }
 846 /* }}} */
 847 
 848 /* {{{ php_oci_statement_cancel()
 849  Cancel statement */
 850 int php_oci_statement_cancel(php_oci_statement *statement)
 851 {
 852         return php_oci_statement_fetch(statement, 0);
 853 }
 854 /* }}} */
 855 
 856 /* {{{ php_oci_statement_free()
 857  Destroy statement handle and free associated resources */
 858 void php_oci_statement_free(php_oci_statement *statement)
 859 {
 860         if (statement->stmt) {
 861                 if (statement->last_query_len) { /* FIXME: magical */
 862                         PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, statement->errcode ? OCI_STRLS_CACHE_DELETE : OCI_DEFAULT));
 863                 } else if (statement->impres_flag != PHP_OCI_IMPRES_IS_CHILD) {  /* Oracle doc says don't free Implicit Result Set handles */
 864                         PHP_OCI_CALL(OCIHandleFree, (statement->stmt, OCI_HTYPE_STMT));
 865                 }
 866                 statement->stmt = NULL;
 867         }
 868 
 869         if (statement->err) {
 870                 PHP_OCI_CALL(OCIHandleFree, (statement->err, OCI_HTYPE_ERROR));
 871                 statement->err = NULL;
 872         }
 873 
 874         if (statement->last_query) {
 875                 efree(statement->last_query);
 876         }
 877 
 878         if (statement->binds) {
 879                 zend_hash_destroy(statement->binds);
 880                 efree(statement->binds);
 881         }
 882 
 883         if (statement->defines) {
 884                 zend_hash_destroy(statement->defines);
 885                 efree(statement->defines);
 886         }
 887 
 888         if (statement->columns) {
 889                 zend_hash_destroy(statement->columns);
 890                 efree(statement->columns);
 891         }
 892 
 893         if (statement->parent_stmtid) {
 894                 zend_list_delete(statement->parent_stmtid);
 895         }
 896 
 897         zend_list_delete(statement->connection->id);
 898         efree(statement);
 899         
 900         OCI_G(num_statements)--;
 901 }
 902 /* }}} */
 903 
 904 /* {{{ php_oci_bind_pre_exec()
 905  Helper function */
 906 int php_oci_bind_pre_exec(zval *data, void *result)
 907 {
 908         php_oci_bind *bind = (php_oci_bind *) Z_PTR_P(data);
 909 
 910         *(int *)result = 0;
 911 
 912         if (Z_TYPE_P(bind->zval) == IS_ARRAY) {
 913                 /* These checks are currently valid for oci_bind_by_name, not
 914                  * oci_bind_array_by_name.  Also bind->type and
 915                  * bind->indicator are not used for oci_bind_array_by_name.
 916                  */
 917                 return 0;
 918         }       
 919         switch (bind->type) {
 920                 case SQLT_NTY:
 921                 case SQLT_BFILEE:
 922                 case SQLT_CFILEE:
 923                 case SQLT_CLOB:
 924                 case SQLT_BLOB:
 925                 case SQLT_RDD:
 926                         if (Z_TYPE_P(bind->zval) != IS_OBJECT) {
 927                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 928                                 *(int *)result = 1;
 929                         }
 930                         break;
 931                         
 932                 case SQLT_CHR:
 933                 case SQLT_AFC:
 934                 case SQLT_INT:
 935                 case SQLT_NUM:
 936 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12
 937                 case SQLT_BOL:
 938 #endif
 939                 case SQLT_LBI:
 940                 case SQLT_BIN:
 941                 case SQLT_LNG:
 942                         if (Z_TYPE_P(bind->zval) == IS_RESOURCE || Z_TYPE_P(bind->zval) == IS_OBJECT) {
 943                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 944                                 *(int *)result = 1;
 945                         }
 946                         break;
 947 
 948                 case SQLT_RSET:
 949                         if (Z_TYPE_P(bind->zval) != IS_RESOURCE) {
 950                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 951                                 *(int *)result = 1;
 952                         }
 953                         break;
 954         }
 955 
 956         /* reset all bind stuff to a normal state... */
 957         bind->indicator = 0;
 958 
 959         return 0;
 960 }
 961 /* }}} */
 962 
 963 /* {{{ php_oci_bind_post_exec()
 964  Helper function */
 965 int php_oci_bind_post_exec(zval *data)
 966 {
 967         php_oci_bind *bind = (php_oci_bind *) Z_PTR_P(data);
 968         php_oci_connection *connection = bind->parent_statement->connection;
 969         sword errstatus;
 970 
 971         if (bind->indicator == -1) { /* NULL */
 972                 zval *val = bind->zval;
 973                 if (Z_TYPE_P(val) == IS_STRING) {
 974                         *Z_STRVAL_P(val) = '\0'; /* XXX avoid warning in debug mode */
 975                 }
 976                 zval_dtor(val);
 977                 ZVAL_NULL(val);
 978         } else if (Z_TYPE_P(bind->zval) == IS_STRING
 979                            && Z_STRLEN_P(bind->zval) > 0
 980                            && Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] != '\0') {
 981                 /* The post- PHP 5.3 feature for "interned" strings disallows
 982                  * their reallocation but (i) any IN binds either interned or
 983                  * not should already be null terminated and (ii) for OUT
 984                  * binds, php_oci_bind_out_callback() should have allocated a
 985                  * new string that we can modify here.
 986                  */
 987                 Z_STR_P(bind->zval) = zend_string_extend(Z_STR_P(bind->zval), Z_STRLEN_P(bind->zval)+1, 0);
 988                 Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] = '\0';
 989         } else if (Z_TYPE_P(bind->zval) == IS_ARRAY) {
 990                 int i;
 991                 zval *entry = NULL;
 992                 HashTable *hash = HASH_OF(bind->zval);
 993         
 994                 zend_hash_internal_pointer_reset(hash);
 995 
 996                 switch (bind->array.type) {
 997                         case SQLT_NUM:
 998                         case SQLT_INT:
 999                         case SQLT_LNG:
1000                                 for (i = 0; i < (int) bind->array.current_length; i++) {
1001                                         if ((i < (int) bind->array.old_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1002                                                 zval_dtor(entry);
1003                                                 ZVAL_LONG(entry, ((ub4 *)(bind->array.elements))[i]);
1004                                                 zend_hash_move_forward(hash);
1005                                         } else {
1006                                                 add_next_index_long(bind->zval, ((ub4 *)(bind->array.elements))[i]);
1007                                         }
1008                                 }
1009                                 break;
1010                         case SQLT_FLT:
1011                                 for (i = 0; i < (int) bind->array.current_length; i++) {
1012                                         if ((i < (int) bind->array.old_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1013                                                 zval_dtor(entry);
1014                                                 ZVAL_DOUBLE(entry, ((double *)(bind->array.elements))[i]);
1015                                                 zend_hash_move_forward(hash);
1016                                         } else {
1017                                                 add_next_index_double(bind->zval, ((double *)(bind->array.elements))[i]);
1018                                         }
1019                                 }
1020                                 break;
1021                         case SQLT_ODT:
1022                                 for (i = 0; i < (int) bind->array.current_length; i++) {
1023                                         oratext buff[1024];
1024                                         ub4 buff_len = 1024;
1025 
1026                                         memset((void*)buff,0,sizeof(buff));
1027                                                         
1028                                         if ((i < (int) bind->array.old_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1029                                                 PHP_OCI_CALL_RETURN(errstatus, OCIDateToText, (connection->err, &(((OCIDate *)(bind->array.elements))[i]), 0, 0, 0, 0, &buff_len, buff));
1030                                                 zval_dtor(entry);
1031 
1032                                                 if (errstatus != OCI_SUCCESS) {
1033                                                         connection->errcode = php_oci_error(connection->err, errstatus);
1034                                                         PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
1035                                                         ZVAL_NULL(entry);
1036                                                 } else {
1037                                                         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1038                                                         ZVAL_STRINGL(entry, (char *)buff, buff_len);
1039                                                 }
1040                                                 zend_hash_move_forward(hash);
1041                                         } else {
1042                                                 PHP_OCI_CALL_RETURN(errstatus, OCIDateToText, (connection->err, &(((OCIDate *)(bind->array.elements))[i]), 0, 0, 0, 0, &buff_len, buff));
1043                                                 if (errstatus != OCI_SUCCESS) {
1044                                                         connection->errcode = php_oci_error(connection->err, errstatus);
1045                                                         PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
1046                                                         add_next_index_null(bind->zval);
1047                                                 } else {
1048                                                         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1049                                                         add_next_index_stringl(bind->zval, (char *)buff, buff_len);
1050                                                 }
1051                                         }
1052                                 }
1053                                 break;
1054         
1055                         case SQLT_AFC:
1056                         case SQLT_CHR:
1057                         case SQLT_VCS:
1058                         case SQLT_AVC:
1059                         case SQLT_STR:
1060                         case SQLT_LVC:
1061                                 for (i = 0; i < (int) bind->array.current_length; i++) {
1062                                         /* int curr_element_length = strlen(((text *)bind->array.elements)+i*bind->array.max_length); */
1063                                         int curr_element_length = bind->array.element_lengths[i];
1064                                         if ((i < (int) bind->array.old_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1065                                                 zval_dtor(entry);
1066                                                 ZVAL_STRINGL(entry, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length);
1067                                                 zend_hash_move_forward(hash);
1068                                         } else {
1069                                                 add_next_index_stringl(bind->zval, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length);
1070                                         }
1071                                 }
1072                                 break;
1073                 }
1074         } else if ((Z_TYPE_P(bind->zval) == IS_TRUE) || (Z_TYPE_P(bind->zval) == IS_FALSE)) {
1075                 if (Z_LVAL_P(bind->zval) == 0)
1076                         ZVAL_BOOL(bind->zval, FALSE);
1077                 else if (Z_LVAL_P(bind->zval) == 1)
1078                         ZVAL_BOOL(bind->zval, TRUE);
1079         }
1080 
1081         return 0;
1082 }
1083 /* }}} */
1084 
1085 /* {{{ php_oci_bind_by_name()
1086  Bind zval to the given placeholder */
1087 int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_len, zval *var, zend_long maxlength, ub2 type)
1088 {
1089         php_oci_collection *bind_collection = NULL;
1090         php_oci_descriptor *bind_descriptor = NULL;
1091         php_oci_statement  *bind_statement      = NULL;
1092         dvoid *oci_desc                                 = NULL;
1093         /* dvoid *php_oci_collection               = NULL; */
1094         OCIStmt *oci_stmt                               = NULL;
1095         dvoid *bind_data                                = NULL;
1096         php_oci_bind *old_bind, *bindp;
1097         int mode = OCI_DATA_AT_EXEC;
1098         sb4 value_sz = -1;
1099         sword errstatus;
1100 
1101         switch (type) {
1102                 case SQLT_NTY:
1103                 {
1104                         zval *tmp;
1105                         
1106                         if (Z_TYPE_P(var) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(var), "collection", sizeof("collection")-1)) == NULL) {
1107                                 php_error_docref(NULL, E_WARNING, "Unable to find collection property");
1108                                 return 1;
1109                         }
1110 
1111                         PHP_OCI_ZVAL_TO_COLLECTION_EX(tmp, bind_collection);
1112                         value_sz = sizeof(void*);
1113                         mode = OCI_DEFAULT;
1114                 
1115                         if (!bind_collection->collection) {
1116                                 return 1;
1117                         }
1118                 }
1119                         break;
1120                 case SQLT_BFILEE:
1121                 case SQLT_CFILEE:
1122                 case SQLT_CLOB:
1123                 case SQLT_BLOB:
1124                 case SQLT_RDD:
1125                 {
1126                         zval *tmp;
1127                         
1128                         if (Z_TYPE_P(var) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor")-1)) == NULL) {
1129                                 php_error_docref(NULL, E_WARNING, "Unable to find descriptor property");
1130                                 return 1;
1131                         }
1132 
1133                         PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(tmp, bind_descriptor);
1134 
1135                         value_sz = sizeof(void*);
1136                         
1137                         oci_desc = bind_descriptor->descriptor;
1138                         
1139                         if (!oci_desc) {
1140                                 return 1;
1141                         }
1142                 }
1143                         break;
1144                         
1145                 case SQLT_INT:
1146                 case SQLT_NUM:
1147                         if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
1148                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
1149                                 return 1;
1150                         }
1151                         convert_to_long(var);
1152 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION > 10
1153                         bind_data = (ub8 *)&Z_LVAL_P(var);
1154                         value_sz = sizeof(ub8);
1155 #else
1156                         bind_data = (ub4 *)&Z_LVAL_P(var);
1157                         value_sz = sizeof(ub4);
1158 #endif
1159                         mode = OCI_DEFAULT;
1160                         break;
1161                         
1162                 case SQLT_LBI:
1163                 case SQLT_BIN:
1164                 case SQLT_LNG:
1165                 case SQLT_AFC:
1166                 case SQLT_CHR: /* SQLT_CHR is the default value when type was not specified */
1167                         if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
1168                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
1169                                 return 1;
1170                         }
1171                         if (Z_TYPE_P(var) != IS_NULL) {
1172                                 convert_to_string(var);
1173                         }
1174                         if ((maxlength == -1) || (maxlength == 0)) {
1175                                 if (type == SQLT_LNG) {
1176                                         value_sz = SB4MAXVAL;
1177                                 } else if (Z_TYPE_P(var) == IS_STRING) {
1178                                         value_sz = (sb4) Z_STRLEN_P(var);
1179                                 } else {
1180                                         value_sz = PHP_OCI_PIECE_SIZE;
1181                                 }
1182                         } else {
1183                                 value_sz = (sb4) maxlength;
1184                         }
1185                         break;
1186 
1187                 case SQLT_RSET:
1188                         if (Z_TYPE_P(var) != IS_RESOURCE) {
1189                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
1190                                 return 1;
1191                         }
1192                         PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement);
1193                         value_sz = sizeof(void*);
1194 
1195                         oci_stmt = bind_statement->stmt;
1196 
1197                         if (!oci_stmt) {
1198                                 return 1;
1199                         }
1200                         break;
1201 
1202 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12
1203                 case SQLT_BOL:
1204                         if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
1205                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
1206                                 return 1;
1207                         }
1208                         convert_to_boolean(var);
1209                         bind_data = (zend_long *)&Z_LVAL_P(var);
1210                         if (Z_TYPE_P(var) == IS_TRUE)
1211                                 *(zend_long *)bind_data = 1;
1212                         else if (Z_TYPE_P(var) == IS_FALSE)
1213                                 *(zend_long *)bind_data = 0;
1214                         else {
1215                                 php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
1216                                 return 1;
1217                         }
1218 
1219                         value_sz = sizeof(zend_long);
1220 
1221                         mode = OCI_DEFAULT;
1222                         break;
1223 #endif
1224 
1225                 default:
1226                         php_error_docref(NULL, E_WARNING, "Unknown or unsupported datatype given: %d", (int)type);
1227                         return 1;
1228                         break;
1229         }
1230 
1231         if (!statement->binds) {
1232                 ALLOC_HASHTABLE(statement->binds);
1233                 zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
1234         }
1235 
1236         if ((old_bind = zend_hash_str_find_ptr(statement->binds, name, name_len)) != NULL) {
1237                 bindp = old_bind;
1238         } else {
1239                 zend_string *zvtmp;
1240                 zvtmp = zend_string_init(name, name_len, 0);
1241                 bindp = (php_oci_bind *) ecalloc(1, sizeof(php_oci_bind));
1242                 bindp = zend_hash_update_ptr(statement->binds, zvtmp, bindp);
1243                 zend_string_release(zvtmp);
1244         }
1245         
1246         bindp->descriptor = oci_desc;
1247         bindp->statement = oci_stmt;
1248         bindp->parent_statement = statement;
1249         bindp->zval = var;
1250         bindp->type = type;
1251         /* Storing max length set in OCIBindByName() to check it later in
1252          * php_oci_bind_in_callback() function to avoid ORA-1406 error while
1253          * executing OCIStmtExecute()
1254      */
1255         bindp->dummy_len = value_sz;
1256 
1257         PHP_OCI_CALL_RETURN(errstatus,
1258                 OCIBindByName,
1259                 (
1260                         statement->stmt,                                 /* statement handle */
1261                         (OCIBind **)&bindp->bind,                /* bind hdl (will alloc) */
1262                         statement->err,                                  /* error handle */
1263                         (text*) name,                                    /* placeholder name */                                 
1264                         (sb4) name_len,                                  /* placeholder length */
1265                         (dvoid *)bind_data,                              /* in/out data */
1266                         value_sz, /* PHP_OCI_MAX_DATA_SIZE, */ /* max size of input/output data */
1267                         type,                                                    /* in/out data type */
1268                         (dvoid *)&bindp->indicator,              /* indicator (ignored) */
1269                         (ub2 *)0,                                                /* size array (ignored) */
1270                         (ub2 *)&bindp->retcode,                  /* return code (ignored) */
1271                         (ub4)0,                                                  /* maxarr_len (PL/SQL only?) */
1272                         (ub4 *)0,                                                /* actual array size (PL/SQL only?) */
1273                         mode                                                     /* mode */
1274                 )
1275         );
1276 
1277         if (errstatus != OCI_SUCCESS) {
1278                 statement->errcode = php_oci_error(statement->err, errstatus);
1279                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1280                 return 1;
1281         }
1282 
1283         if (mode == OCI_DATA_AT_EXEC) {
1284                 PHP_OCI_CALL_RETURN(errstatus, OCIBindDynamic,
1285                                 (
1286                                  bindp->bind,
1287                                  statement->err,
1288                                  (dvoid *)bindp,
1289                                  php_oci_bind_in_callback,
1290                                  (dvoid *)bindp,
1291                                  php_oci_bind_out_callback
1292                                 )
1293                 );
1294 
1295                 if (errstatus != OCI_SUCCESS) {
1296                         statement->errcode = php_oci_error(statement->err, errstatus);
1297                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1298                         return 1;
1299                 }
1300         }
1301 
1302         if (type == SQLT_NTY) {
1303                 /* Bind object */
1304                 PHP_OCI_CALL_RETURN(errstatus, OCIBindObject,
1305                                 (
1306                                  bindp->bind,
1307                                  statement->err,
1308                                  bind_collection->tdo,
1309                                  (dvoid **) &(bind_collection->collection),
1310                                  (ub4 *) 0,
1311                                  (dvoid **) 0,
1312                                  (ub4 *) 0
1313                                 )
1314                 );
1315                 
1316                 if (errstatus) {
1317                         statement->errcode = php_oci_error(statement->err, errstatus);
1318                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1319                         return 1;
1320                 }
1321         }
1322         
1323         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1324         return 0;
1325 }
1326 /* }}} */
1327 
1328 /* {{{ php_oci_bind_in_callback()
1329  Callback used when binding LOBs and VARCHARs */
1330 sb4 php_oci_bind_in_callback(
1331                                         dvoid *ictxp,     /* context pointer */
1332                                         OCIBind *bindp,   /* bind handle */
1333                                         ub4 iter,                 /* 0-based execute iteration value */
1334                                         ub4 index,                /* index of current array for PL/SQL or row index for SQL */
1335                                         dvoid **bufpp,    /* pointer to data */
1336                                         ub4 *alenp,               /* size after value/piece has been read */
1337                                         ub1 *piecep,      /* which piece */
1338                                         dvoid **indpp)    /* indicator value */
1339 {
1340         php_oci_bind *phpbind;
1341         zval *val;
1342 
1343         if (!(phpbind=(php_oci_bind *)ictxp) || !(val = phpbind->zval)) {
1344                 php_error_docref(NULL, E_WARNING, "Invalid phpbind pointer value");
1345                 return OCI_ERROR;
1346         }
1347 
1348         if (Z_ISNULL_P(val)) {
1349                 /* we're going to insert a NULL column */
1350                 phpbind->indicator = -1;
1351                 *bufpp = 0;
1352                 *alenp = -1;
1353                 *indpp = (dvoid *)&phpbind->indicator;
1354         } else  if ((phpbind->descriptor == 0) && (phpbind->statement == 0)) {
1355                 /* "normal string bind */
1356                 convert_to_string(val);
1357 
1358                 *bufpp = Z_STRVAL_P(val);
1359                 *alenp = (ub4) Z_STRLEN_P(val);
1360                 /*
1361                  * bind_char_1: If max length set in OCIBindByName is less than the
1362                  * actual length of input string, then we have to overwrite alenp with
1363                  * max value set in OCIBindByName (dummy_len). Or else it will cause
1364                  * ORA-1406 error in OCIStmtExecute
1365                  */
1366                 if ((phpbind->dummy_len > 0) && (phpbind->dummy_len < *alenp))
1367                         *alenp = phpbind->dummy_len;
1368                 *indpp = (dvoid *)&phpbind->indicator;
1369         } else if (phpbind->statement != 0) {
1370                 /* RSET */
1371                 *bufpp = phpbind->statement;
1372                 *alenp = -1;            /* seems to be allright */
1373                 *indpp = (dvoid *)&phpbind->indicator;
1374         } else {
1375                 /* descriptor bind */
1376                 *bufpp = phpbind->descriptor;
1377                 *alenp = -1;            /* seems to be allright */
1378                 *indpp = (dvoid *)&phpbind->indicator;
1379         }
1380 
1381         *piecep = OCI_ONE_PIECE; /* pass all data in one go */
1382 
1383         return OCI_CONTINUE;
1384 }
1385 /* }}} */
1386 
1387 /* {{{ php_oci_bind_out_callback()
1388  Callback used when binding LOBs and VARCHARs */
1389 sb4 php_oci_bind_out_callback(
1390                                         dvoid *octxp,      /* context pointer */
1391                                         OCIBind *bindp,    /* bind handle */
1392                                         ub4 iter,                  /* 0-based execute iteration value */
1393                                         ub4 index,                 /* index of current array for PL/SQL or row index for SQL */
1394                                         dvoid **bufpp,     /* pointer to data */
1395                                         ub4 **alenpp,      /* size after value/piece has been read */
1396                                         ub1 *piecep,       /* which piece */
1397                                         dvoid **indpp,     /* indicator value */
1398                                         ub2 **rcodepp)     /* return code */
1399 {
1400         php_oci_bind *phpbind;
1401         zval *val;
1402         sb4 retval = OCI_ERROR;
1403 
1404         if (!(phpbind=(php_oci_bind *)octxp) || !(val = phpbind->zval)) {
1405                 php_error_docref(NULL, E_WARNING, "Invalid phpbind pointer value");
1406                 return retval;
1407         }
1408 
1409         if (Z_TYPE_P(val) == IS_RESOURCE) {
1410                 /* Processing for ref-cursor out binds */
1411                 if (phpbind->statement != NULL) {
1412                         *bufpp = phpbind->statement;
1413                         *alenpp = &phpbind->dummy_len;
1414                         *piecep = OCI_ONE_PIECE;
1415                         *rcodepp = &phpbind->retcode;
1416                         *indpp = &phpbind->indicator;
1417                 }
1418                 retval = OCI_CONTINUE;
1419         } else if (Z_TYPE_P(val) == IS_OBJECT) {
1420                 zval *tmp;
1421                 php_oci_descriptor *desc;
1422 
1423                 if (!phpbind->descriptor) {
1424                         return OCI_ERROR;
1425                 }
1426 
1427                 /* Do not use the cached lob size if the descriptor is an
1428                  * out-bind as the contents would have been changed for in/out
1429                  * binds (Bug #46994).
1430                  */
1431                 if ((tmp = zend_hash_str_find(Z_OBJPROP_P(val), "descriptor", sizeof("descriptor")-1)) == NULL) {
1432                         php_error_docref(NULL, E_WARNING, "Unable to find object outbind descriptor property");
1433                         return OCI_ERROR;
1434                 }
1435                 PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(tmp, desc);
1436                 desc->lob_size = -1;    /* force OCI8 to update cached size */
1437 
1438                 *alenpp = &phpbind->dummy_len;
1439                 *bufpp = phpbind->descriptor;
1440                 *piecep = OCI_ONE_PIECE;
1441                 *rcodepp = &phpbind->retcode;
1442                 *indpp = &phpbind->indicator;
1443                 retval = OCI_CONTINUE;
1444         } else {
1445                 convert_to_string(val);
1446                 zval_dtor(val);
1447 
1448                 {
1449                         char *p = ecalloc(1, PHP_OCI_PIECE_SIZE);
1450                         ZVAL_STRINGL(val, p, PHP_OCI_PIECE_SIZE);
1451                         efree(p);
1452                 }
1453 #if 0
1454                 Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
1455                 Z_STRVAL_P(val) = ecalloc(1, Z_STRLEN_P(val) + 1);
1456                 /* XXX is this right? */
1457                 ZVAL_STRINGL(val, NULL, Z_STRLEN(phpbind->zval) + 1);
1458 #endif          
1459 
1460                 /* XXX we assume that zend-zval len has 4 bytes */
1461                 *alenpp = (ub4*) &Z_STRLEN_P(phpbind->zval);
1462                 *bufpp = Z_STRVAL_P(phpbind->zval);
1463                 *piecep = OCI_ONE_PIECE;
1464                 *rcodepp = &phpbind->retcode;
1465                 *indpp = &phpbind->indicator;
1466                 retval = OCI_CONTINUE;
1467         }
1468 
1469         return retval;
1470 }
1471 /* }}} */
1472 
1473 /* {{{ php_oci_statement_get_column_helper()
1474  Helper function to get column by name and index */
1475 php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAMETERS, int need_data)
1476 {
1477         zval *z_statement, *column_index;
1478         php_oci_statement *statement;
1479         php_oci_out_column *column;
1480 
1481         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &z_statement, &column_index) == FAILURE) {
1482                 return NULL;
1483         }
1484 
1485         statement = (php_oci_statement *) zend_fetch_resource_ex(z_statement, "oci8 statement", le_statement);
1486 
1487         if (!statement) {
1488                 return NULL;
1489         }
1490 
1491         if (need_data && !statement->has_data) {
1492                 return NULL;
1493         }
1494         
1495         if (Z_TYPE_P(column_index) == IS_STRING) {
1496                 column = php_oci_statement_get_column(statement, -1, Z_STRVAL_P(column_index), (int) Z_STRLEN_P(column_index));
1497                 if (!column) {
1498                         php_error_docref(NULL, E_WARNING, "Invalid column name \"%s\"", Z_STRVAL_P(column_index));
1499                         return NULL;
1500                 }
1501         } else {
1502                 zval tmp;
1503                 /* NB: for PHP4 compat only, it should be using 'Z' instead */
1504                 tmp = *column_index;
1505                 zval_copy_ctor(&tmp);
1506                 convert_to_long(&tmp);
1507                 column = php_oci_statement_get_column(statement, Z_LVAL(tmp), NULL, 0);
1508                 if (!column) {
1509                         php_error_docref(NULL, E_WARNING, "Invalid column index \"%pd\"", Z_LVAL(tmp));
1510                         zval_dtor(&tmp);
1511                         return NULL;
1512                 }
1513                 zval_dtor(&tmp);
1514         }
1515         return column;
1516 }
1517 /* }}} */
1518 
1519 /* {{{ php_oci_statement_get_type()
1520  Return type of the statement */
1521 int php_oci_statement_get_type(php_oci_statement *statement, ub2 *type)
1522 {
1523         ub2 statement_type;
1524         sword errstatus;
1525         
1526         *type = 0;
1527         
1528         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement_type, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
1529 
1530         if (errstatus != OCI_SUCCESS) {
1531                 statement->errcode = php_oci_error(statement->err, errstatus);
1532                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1533                 return 1;
1534         }
1535         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1536         *type = statement_type;
1537 
1538         return 0;
1539 }
1540 /* }}} */
1541 
1542 /* {{{ php_oci_statement_get_numrows()
1543  Get the number of rows fetched to the clientside (NOT the number of rows in the result set) */
1544 int php_oci_statement_get_numrows(php_oci_statement *statement, ub4 *numrows)
1545 {
1546         ub4 statement_numrows;
1547         sword errstatus;
1548         
1549         *numrows = 0;
1550         
1551         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub4 *)&statement_numrows, (ub4 *)0, OCI_ATTR_ROW_COUNT, statement->err));
1552 
1553         if (errstatus != OCI_SUCCESS) {
1554                 statement->errcode = php_oci_error(statement->err, errstatus);
1555                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1556                 return 1;
1557         }
1558         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1559         *numrows = statement_numrows;
1560 
1561         return 0;
1562 }
1563 /* }}} */
1564 
1565 /* {{{ php_oci_bind_array_by_name()
1566  Bind arrays to PL/SQL types */
1567 int php_oci_bind_array_by_name(php_oci_statement *statement, char *name, size_t name_len, zval *var, zend_long max_table_length, zend_long maxlength, zend_long type)
1568 {
1569         php_oci_bind *bind, *bindp;
1570         sword errstatus;
1571         zend_string *zvtmp;
1572 
1573         convert_to_array(var);
1574 
1575         if (maxlength < -1) {
1576                 php_error_docref(NULL, E_WARNING, "Invalid max length value (%pd)", maxlength);
1577                 return 1;
1578         }
1579         
1580         switch(type) {
1581                 case SQLT_NUM:
1582                 case SQLT_INT:
1583                 case SQLT_LNG:
1584                         bind = php_oci_bind_array_helper_number(var, max_table_length);
1585                         break;
1586 
1587                 case SQLT_FLT:
1588                         bind = php_oci_bind_array_helper_double(var, max_table_length);
1589                         break;
1590                         
1591                 case SQLT_AFC:
1592                 case SQLT_CHR:
1593                 case SQLT_VCS:
1594                 case SQLT_AVC:
1595                 case SQLT_STR:
1596                 case SQLT_LVC:
1597                         if (maxlength == -1 && zend_hash_num_elements(Z_ARRVAL_P(var)) == 0) {
1598                                 php_error_docref(NULL, E_WARNING, "You must provide max length value for empty arrays");
1599                                 return 1;
1600                         }
1601                         bind = php_oci_bind_array_helper_string(var, max_table_length, maxlength);
1602                         break;
1603                 case SQLT_ODT:
1604                         bind = php_oci_bind_array_helper_date(var, max_table_length, statement->connection);
1605                         break;
1606                 default:
1607                         php_error_docref(NULL, E_WARNING, "Unknown or unsupported datatype given: %pd", type);
1608                         return 1;
1609                         break;
1610         }
1611 
1612         if (bind == NULL) {
1613                 /* failed to generate bind struct */
1614                 return 1;
1615         }
1616         
1617         bind->descriptor = NULL;
1618         bind->statement = NULL;
1619         bind->parent_statement = statement;
1620         bind->bind = NULL;
1621         bind->zval = var;
1622         bind->array.type = type;
1623         bind->indicator = 0;            /* not used for array binds */
1624         bind->type = 0;                         /* not used for array binds */
1625 
1626         PHP_OCI_CALL_RETURN(errstatus,
1627                                                         OCIBindByName,
1628                                                         (
1629                                                                 statement->stmt,
1630                                                                 (OCIBind **)&bind->bind,
1631                                                                 statement->err,
1632                                                                 (text *)name,
1633                                                                 (sb4) name_len,
1634                                                                 (dvoid *) bind->array.elements,
1635                                                                 (sb4) bind->array.max_length,
1636                                                                 (ub2)type,
1637                                                                 (dvoid *)bind->array.indicators,
1638                                                                 (ub2 *)bind->array.element_lengths,
1639                                                                 (ub2 *)0, /* bindp->array.retcodes, */
1640                                                                 (ub4) max_table_length,
1641                                                                 (ub4 *) &(bind->array.current_length),
1642                                                                 (ub4) OCI_DEFAULT
1643                                                         )
1644                                                 );
1645         
1646                 
1647         if (errstatus != OCI_SUCCESS) {
1648                 if (bind->array.elements) {
1649                         efree(bind->array.elements);
1650                 }
1651 
1652                 if (bind->array.element_lengths) {
1653                         efree(bind->array.element_lengths);
1654                 }
1655 
1656                 if (bind->array.indicators) {
1657                         efree(bind->array.indicators);
1658                 }
1659 
1660                 efree(bind);
1661 
1662                 statement->errcode = php_oci_error(statement->err, errstatus);
1663                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1664                 return 1;
1665         }
1666 
1667         if (!statement->binds) {
1668                 ALLOC_HASHTABLE(statement->binds);
1669                 zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
1670         }
1671 
1672         zvtmp = zend_string_init(name, name_len, 0);
1673         bindp = zend_hash_update_ptr(statement->binds, zvtmp, bind);
1674         zend_string_release(zvtmp);
1675 
1676         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1677         return 0;
1678 }
1679 /* }}} */
1680 
1681 /* {{{ php_oci_bind_array_helper_string()
1682  Bind arrays to PL/SQL types */
1683 php_oci_bind *php_oci_bind_array_helper_string(zval *var, zend_long max_table_length, zend_long maxlength)
1684 {
1685         php_oci_bind *bind;
1686         ub4 i;
1687         HashTable *hash;
1688         zval *entry;
1689 
1690         hash = HASH_OF(var);
1691 
1692         if (maxlength == -1) {
1693                 zend_hash_internal_pointer_reset(hash);
1694                 while ((entry = zend_hash_get_current_data(hash)) != NULL) {
1695                         convert_to_string_ex(entry);
1696 
1697                         if (maxlength == -1 || Z_STRLEN_P(entry) > (size_t) maxlength) {
1698                                 maxlength = Z_STRLEN_P(entry) + 1;
1699                         }
1700 
1701                         zend_hash_move_forward(hash);
1702                 }
1703         }
1704         
1705         bind = emalloc(sizeof(php_oci_bind));
1706         bind->array.elements            = (text *)safe_emalloc(max_table_length * (maxlength + 1), sizeof(text), 0);
1707         memset(bind->array.elements, 0, max_table_length * (maxlength + 1) * sizeof(text));
1708         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1709         bind->array.old_length          = bind->array.current_length;
1710         bind->array.max_length          = (ub4) maxlength;
1711         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1712         memset(bind->array.element_lengths, 0, max_table_length*sizeof(ub2));
1713         bind->array.indicators          = safe_emalloc(max_table_length, sizeof(sb2), 0);
1714         memset(bind->array.indicators, 0, max_table_length*sizeof(sb2));
1715         
1716         zend_hash_internal_pointer_reset(hash);
1717         
1718         for (i = 0; i < bind->array.current_length; i++) {
1719                 if ((entry = zend_hash_get_current_data(hash)) != NULL) {
1720                         convert_to_string_ex(entry);
1721                         bind->array.element_lengths[i] = (ub2) Z_STRLEN_P(entry);
1722                         if (Z_STRLEN_P(entry) == 0) {
1723                                 bind->array.indicators[i] = -1;
1724                         }
1725                         zend_hash_move_forward(hash);
1726                 } else {
1727                         break;
1728                 }
1729         }
1730 
1731         zend_hash_internal_pointer_reset(hash);
1732         for (i = 0; i < max_table_length; i++) {
1733                 if ((i < bind->array.current_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1734                         int element_length;
1735                         
1736                         convert_to_string_ex(entry);
1737                         element_length = ((size_t) maxlength > Z_STRLEN_P(entry)) ? (int) Z_STRLEN_P(entry) : (int) maxlength;
1738                         
1739                         memcpy((text *)bind->array.elements + i*maxlength, Z_STRVAL_P(entry), element_length);
1740                         ((text *)bind->array.elements)[i*maxlength + element_length] = '\0';
1741                         
1742                         zend_hash_move_forward(hash);
1743                 } else {
1744                         ((text *)bind->array.elements)[i*maxlength] = '\0';
1745                 }
1746         }
1747         zend_hash_internal_pointer_reset(hash);
1748 
1749         return bind;
1750 }
1751 /* }}} */
1752 
1753 /* {{{ php_oci_bind_array_helper_number()
1754  Bind arrays to PL/SQL types */
1755 php_oci_bind *php_oci_bind_array_helper_number(zval *var, zend_long max_table_length)
1756 {
1757         php_oci_bind *bind;
1758         ub4 i;
1759         HashTable *hash;
1760         zval *entry;
1761 
1762         hash = HASH_OF(var);
1763 
1764         bind = emalloc(sizeof(php_oci_bind));
1765         bind->array.elements            = (ub4 *)safe_emalloc(max_table_length, sizeof(ub4), 0);
1766         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1767         bind->array.old_length          = bind->array.current_length;
1768         bind->array.max_length          = sizeof(ub4);
1769         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1770         memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
1771         bind->array.indicators          = NULL;
1772         
1773         zend_hash_internal_pointer_reset(hash);
1774         for (i = 0; i < max_table_length; i++) {
1775                 if (i < bind->array.current_length) {
1776                         bind->array.element_lengths[i] = sizeof(ub4);
1777                 }
1778                 if ((i < bind->array.current_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1779                         convert_to_long_ex(entry);
1780                         ((ub4 *)bind->array.elements)[i] = (ub4) Z_LVAL_P(entry);
1781                         zend_hash_move_forward(hash);
1782                 } else {
1783                         ((ub4 *)bind->array.elements)[i] = 0;
1784                 }
1785         }
1786         zend_hash_internal_pointer_reset(hash);
1787 
1788         return bind;
1789 }
1790 /* }}} */
1791 
1792 /* {{{ php_oci_bind_array_helper_double()
1793  Bind arrays to PL/SQL types */
1794 php_oci_bind *php_oci_bind_array_helper_double(zval *var, zend_long max_table_length)
1795 {
1796         php_oci_bind *bind;
1797         ub4 i;
1798         HashTable *hash;
1799         zval *entry;
1800 
1801         hash = HASH_OF(var);
1802 
1803         bind = emalloc(sizeof(php_oci_bind));
1804         bind->array.elements            = (double *)safe_emalloc(max_table_length, sizeof(double), 0);
1805         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1806         bind->array.old_length          = bind->array.current_length;
1807         bind->array.max_length          = sizeof(double);
1808         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1809         memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
1810         bind->array.indicators          = NULL;
1811         
1812         zend_hash_internal_pointer_reset(hash);
1813         for (i = 0; i < max_table_length; i++) {
1814                 if (i < bind->array.current_length) {
1815                         bind->array.element_lengths[i] = sizeof(double);
1816                 }
1817                 if ((i < bind->array.current_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1818                         convert_to_double_ex(entry);
1819                         ((double *)bind->array.elements)[i] = (double) Z_DVAL_P(entry);
1820                         zend_hash_move_forward(hash);
1821                 } else {
1822                         ((double *)bind->array.elements)[i] = 0;
1823                 }
1824         }
1825         zend_hash_internal_pointer_reset(hash);
1826 
1827         return bind;
1828 }
1829 /* }}} */
1830 
1831 /* {{{ php_oci_bind_array_helper_date()
1832  Bind arrays to PL/SQL types */
1833 php_oci_bind *php_oci_bind_array_helper_date(zval *var, zend_long max_table_length, php_oci_connection *connection)
1834 {
1835         php_oci_bind *bind;
1836         ub4 i;
1837         HashTable *hash;
1838         zval *entry;
1839         sword errstatus;
1840 
1841         hash = HASH_OF(var);
1842 
1843         bind = emalloc(sizeof(php_oci_bind));
1844         bind->array.elements            = (OCIDate *)safe_emalloc(max_table_length, sizeof(OCIDate), 0);
1845         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1846         bind->array.old_length          = bind->array.current_length;
1847         bind->array.max_length          = sizeof(OCIDate);
1848         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1849         memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
1850         bind->array.indicators          = NULL;
1851 
1852         zend_hash_internal_pointer_reset(hash);
1853         for (i = 0; i < max_table_length; i++) {
1854                 OCIDate oci_date;
1855                 if (i < bind->array.current_length) {
1856                         bind->array.element_lengths[i] = sizeof(OCIDate);
1857                 }
1858                 if ((i < bind->array.current_length) && (entry = zend_hash_get_current_data(hash)) != NULL) {
1859                         
1860                         convert_to_string_ex(entry);
1861                         PHP_OCI_CALL_RETURN(errstatus, OCIDateFromText, (connection->err, (CONST text *)Z_STRVAL_P(entry), (ub4) Z_STRLEN_P(entry), NULL, 0, NULL, 0, &oci_date));
1862 
1863                         if (errstatus != OCI_SUCCESS) {
1864                                 /* failed to convert string to date */
1865                                 efree(bind->array.element_lengths);
1866                                 efree(bind->array.elements);
1867                                 efree(bind);
1868                                 connection->errcode = php_oci_error(connection->err, errstatus);
1869                                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
1870                                 return NULL;
1871                         }
1872                         
1873                         ((OCIDate *)bind->array.elements)[i] = oci_date;
1874                         zend_hash_move_forward(hash);
1875                 } else {
1876                         PHP_OCI_CALL_RETURN(errstatus, OCIDateFromText, (connection->err, (CONST text *)"01-JAN-00", sizeof("01-JAN-00")-1, NULL, 0, NULL, 0, &oci_date));
1877 
1878                         if (errstatus != OCI_SUCCESS) {
1879                                 /* failed to convert string to date */
1880                                 efree(bind->array.element_lengths);
1881                                 efree(bind->array.elements);
1882                                 efree(bind);
1883                                 connection->errcode = php_oci_error(connection->err, errstatus);
1884                                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
1885                                 return NULL;
1886                         }
1887         
1888                         ((OCIDate *)bind->array.elements)[i] = oci_date;
1889                 }
1890                 connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1891         }
1892         zend_hash_internal_pointer_reset(hash);
1893 
1894         return bind;
1895 }
1896 /* }}} */
1897 
1898 #endif /* HAVE_OCI8 */
1899 
1900 /*
1901  * Local variables:
1902  * tab-width: 4
1903  * c-basic-offset: 4
1904  * End:
1905  * vim600: noet sw=4 ts=4 fdm=marker
1906  * vim<600: noet sw=4 ts=4
1907  */

/* [<][>][^][v][top][bottom][index][help] */