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 5                                                        |
   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 TSRMLS_DC)
  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 TSRMLS_CC);
  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 = estrndup(query, query_len);
  95                 statement->last_query_len = query_len;
  96         }
  97         else {
  98                 statement->last_query = NULL;
  99                 statement->last_query_len = 0;
 100         }
 101 
 102         statement->connection = connection;
 103         statement->has_data = 0;
 104         statement->has_descr = 0;
 105         statement->parent_stmtid = 0;
 106         statement->impres_child_stmt = NULL;
 107         statement->impres_count = 0;
 108         statement->impres_flag = PHP_OCI_IMPRES_UNKNOWN;  /* may or may not have Implicit Result Set children */
 109         zend_list_addref(statement->connection->id);
 110 
 111         if (OCI_G(default_prefetch) >= 0) {
 112                 php_oci_statement_set_prefetch(statement, (ub4)OCI_G(default_prefetch) TSRMLS_CC);
 113         } else {
 114                 php_oci_statement_set_prefetch(statement, (ub4)100 TSRMLS_CC); /* semi-arbitrary, "sensible default" */
 115         }
 116         
 117         PHP_OCI_REGISTER_RESOURCE(statement, le_statement);
 118 
 119         OCI_G(num_statements)++;
 120         
 121         return statement;
 122 }
 123 /* }}} */
 124 
 125 /* {{{ php_oci_get_implicit_resultset()
 126    Fetch implicit result set statement resource */
 127 php_oci_statement *php_oci_get_implicit_resultset(php_oci_statement *statement TSRMLS_DC)
 128 {
 129 #if (OCI_MAJOR_VERSION < 12)
 130         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Implicit results are available in Oracle Database 12c onwards");
 131         return NULL;
 132 #else
 133         void *result;
 134         ub4   rtype;
 135         php_oci_statement *statement2;  /* implicit result set statement handle */
 136         sword errstatus;
 137 
 138         PHP_OCI_CALL_RETURN(errstatus, OCIStmtGetNextResult, (statement->stmt, statement->err, &result, &rtype, OCI_DEFAULT));
 139         if (errstatus == OCI_NO_DATA) {
 140                 return NULL;
 141         }
 142 
 143         if (rtype != OCI_RESULT_TYPE_SELECT) {
 144                 /* Only OCI_RESULT_TYPE_SELECT is supported by Oracle DB 12cR1 */
 145                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected implicit result type returned from Oracle Database");
 146                 return NULL;
 147         } else {
 148                 statement2 = ecalloc(1,sizeof(php_oci_statement));
 149 
 150                 PHP_OCI_CALL(OCIHandleAlloc, (statement->connection->env, (dvoid **)&(statement2->err), OCI_HTYPE_ERROR, 0, NULL));
 151                 statement2->stmt = (OCIStmt *)result;   
 152                 statement2->parent_stmtid = statement->id;
 153                 statement2->impres_child_stmt = NULL;
 154                 statement2->impres_count = 0;
 155                 statement2->impres_flag = PHP_OCI_IMPRES_IS_CHILD;
 156                 statement2->connection = statement->connection;
 157                 statement2->errcode = 0;
 158                 statement2->last_query = NULL;
 159                 statement2->last_query_len = 0;
 160                 statement2->columns = NULL;
 161                 statement2->binds = NULL;
 162                 statement2->defines = NULL;
 163                 statement2->ncolumns = 0;
 164                 statement2->executed = 0;
 165                 statement2->has_data = 0;
 166                 statement2->has_descr = 0;
 167                 statement2->stmttype = 0;
 168 
 169                 zend_list_addref(statement->id);
 170                 zend_list_addref(statement2->connection->id);
 171 
 172                 php_oci_statement_set_prefetch(statement2, statement->prefetch_count TSRMLS_CC);
 173                 
 174                 PHP_OCI_REGISTER_RESOURCE(statement2, le_statement);
 175         
 176                 OCI_G(num_statements)++;
 177                 
 178                 return statement2;
 179         }
 180 #endif /* OCI_MAJOR_VERSION < 12 */
 181 }
 182 /* }}} */
 183 
 184 /* {{{ php_oci_statement_set_prefetch()
 185  Set prefetch buffer size for the statement */
 186 int php_oci_statement_set_prefetch(php_oci_statement *statement, ub4 prefetch  TSRMLS_DC)
 187 {
 188         sword errstatus;
 189 
 190         if (prefetch > 20000) {
 191                 prefetch = 20000;               /* keep it somewhat sane */
 192         }
 193 
 194         PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (statement->stmt, OCI_HTYPE_STMT, &prefetch, 0, OCI_ATTR_PREFETCH_ROWS, statement->err));
 195         
 196         if (errstatus != OCI_SUCCESS) {
 197                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 198                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 199                 statement->prefetch_count = 0;
 200                 return 1;
 201         }
 202         statement->prefetch_count = prefetch;
 203         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 204         return 0;
 205 }
 206 /* }}} */
 207 
 208 /* {{{ php_oci_cleanup_pre_fetch()
 209    Helper function to cleanup ref-cursors and descriptors from the previous row */
 210 int php_oci_cleanup_pre_fetch(void *data TSRMLS_DC)
 211 {
 212         php_oci_out_column *outcol = data;
 213 
 214         if (!outcol->is_descr && !outcol->is_cursor)
 215                 return ZEND_HASH_APPLY_KEEP;
 216 
 217         switch(outcol->data_type) {
 218                 case SQLT_CLOB:
 219                 case SQLT_BLOB:
 220                 case SQLT_RDD:
 221                 case SQLT_BFILE:
 222                         if (outcol->descid) {
 223                                 zend_list_delete(outcol->descid);
 224                                 outcol->descid = 0;
 225                         }
 226                         break;
 227                 case SQLT_RSET:
 228                         if (outcol->stmtid) {
 229                                 zend_list_delete(outcol->stmtid);
 230                                 outcol->stmtid = 0;
 231                                 outcol->nested_statement = NULL;
 232                         }
 233                         break;
 234                 default:
 235                         break;
 236         }
 237         return ZEND_HASH_APPLY_KEEP;
 238 
 239 }
 240 /* }}} */
 241 
 242 /* {{{ php_oci_statement_fetch()
 243  Fetch a row from the statement */
 244 int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows TSRMLS_DC)
 245 {
 246         int i;
 247         void *handlepp;
 248         ub4 typep, iterp, idxp;
 249         ub1 in_outp, piecep;
 250         zend_bool piecewisecols = 0;
 251         php_oci_out_column *column;
 252         sword errstatus;
 253 
 254         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 255 
 256         if (statement->has_descr && statement->columns) {
 257                 zend_hash_apply(statement->columns, (apply_func_t) php_oci_cleanup_pre_fetch TSRMLS_CC);
 258     }
 259 
 260         PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
 261 
 262         if (errstatus == OCI_NO_DATA || nrows == 0) {
 263                 if (statement->last_query == NULL) {
 264                         /* reset define-list for refcursors */
 265                         if (statement->columns) {
 266                                 zend_hash_destroy(statement->columns);
 267                                 efree(statement->columns);
 268                                 statement->columns = NULL;
 269                                 statement->ncolumns = 0;
 270                         }
 271                         statement->executed = 0;
 272                 }
 273 
 274                 statement->has_data = 0;
 275 
 276                 if (nrows == 0) {
 277                         /* this is exactly what we requested */
 278                         return 0;
 279                 }
 280                 return 1;
 281         }
 282 
 283         /* reset length for all piecewise columns */
 284         for (i = 0; i < statement->ncolumns; i++) {
 285                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
 286                 if (column && column->piecewise) {
 287                         column->retlen4 = 0;
 288                         piecewisecols = 1;
 289                 }
 290         }
 291         
 292         while (errstatus == OCI_NEED_DATA) {
 293                 if (piecewisecols) {
 294                         PHP_OCI_CALL_RETURN(errstatus,
 295                                 OCIStmtGetPieceInfo,
 296                                    (
 297                                         statement->stmt,
 298                                         statement->err,
 299                                         &handlepp,
 300                                         &typep,
 301                                         &in_outp,
 302                                         &iterp,
 303                                         &idxp,
 304                                         &piecep
 305                                    )
 306                         );
 307 
 308                         /* scan through our columns for a piecewise column with a matching handle */
 309                         for (i = 0; i < statement->ncolumns; i++) {
 310                                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
 311                                 if (column && column->piecewise && handlepp == column->oci_define)   {
 312                                         if (!column->data) {
 313                                                 column->data = (text *) ecalloc(1, PHP_OCI_PIECE_SIZE + 1);
 314                                         } else {
 315                                                 column->data = erealloc(column->data, column->retlen4 + PHP_OCI_PIECE_SIZE + 1);
 316                                         }
 317                                         column->cb_retlen = PHP_OCI_PIECE_SIZE;
 318 
 319                                         /* and instruct fetch to fetch waiting piece into our buffer */
 320                                         PHP_OCI_CALL(OCIStmtSetPieceInfo,
 321                                                    (
 322                                                         (void *) column->oci_define,
 323                                                         OCI_HTYPE_DEFINE,
 324                                                         statement->err,
 325                                                         ((char*)column->data) + column->retlen4,
 326                                                         &(column->cb_retlen),
 327                                                         piecep,
 328                                                         &column->indicator,
 329                                                         &column->retcode
 330                                                    )
 331                                         );
 332                                 }
 333                         }
 334                 }
 335 
 336                 PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
 337 
 338                 if (piecewisecols) {
 339                         for (i = 0; i < statement->ncolumns; i++) {
 340                                 column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
 341                                 if (column && column->piecewise && handlepp == column->oci_define)      {
 342                                         column->retlen4 += column->cb_retlen;
 343                                 }
 344                         }
 345                 }
 346         }
 347 
 348         if (errstatus == OCI_SUCCESS_WITH_INFO || errstatus == OCI_SUCCESS) {
 349                 statement->has_data = 1;
 350 
 351                 /* do the stuff needed for OCIDefineByName */
 352                 for (i = 0; i < statement->ncolumns; i++) {
 353                         column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
 354                         if (column == NULL) {
 355                                 continue;
 356                         }
 357                         
 358                         if (!column->define) {
 359                                 continue;
 360                         }
 361                         
 362                         zval_dtor(column->define->zval);
 363                         php_oci_column_to_zval(column, column->define->zval, 0 TSRMLS_CC);
 364                 }
 365 
 366                 return 0;
 367         }
 368 
 369         statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 370         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 371 
 372         statement->has_data = 0;
 373 
 374         return 1;
 375 }
 376 /* }}} */
 377 
 378 /* {{{ php_oci_statement_get_column()
 379  Get column from the result set */
 380 php_oci_out_column *php_oci_statement_get_column(php_oci_statement *statement, long column_index, char *column_name, int column_name_len TSRMLS_DC)
 381 {
 382         php_oci_out_column *column = NULL;
 383         int i;
 384 
 385         if (statement->columns == NULL) { /* we release the columns at the end of a fetch */
 386                 return NULL;
 387         }
 388 
 389         if (column_name) {
 390                 for (i = 0; i < statement->ncolumns; i++) {
 391                         column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
 392                         if (column == NULL) {
 393                                 continue;
 394                         } else if (((int) column->name_len == column_name_len) && (!strncmp(column->name, column_name, column_name_len))) {
 395                                 return column;
 396                         }
 397                 }
 398         } else if (column_index != -1) {
 399                 if (zend_hash_index_find(statement->columns, column_index, (void **)&column) == FAILURE) {
 400                         return NULL;
 401                 }
 402                 return column;
 403         }
 404 
 405         return NULL;
 406 }
 407 /* }}} */
 408 
 409 /* {{{ php_oci_define_callback() */
 410 sb4 php_oci_define_callback(dvoid *ctx, OCIDefine *define, ub4 iter, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
 411 {
 412         php_oci_out_column *outcol = (php_oci_out_column *)ctx;
 413         TSRMLS_FETCH();
 414 
 415         if (!outcol) {
 416                 
 417                 php_error_docref(NULL TSRMLS_CC, 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 TSRMLS_CC);
 426                                 if (!nested_stmt) {
 427                                         return OCI_ERROR;
 428                                 }
 429                                 nested_stmt->parent_stmtid = outcol->statement->id;
 430                                 zend_list_addref(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 TSRMLS_CC);
 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 TSRMLS_DC)
 481 {
 482         php_oci_out_column *outcol;
 483         php_oci_out_column column;
 484         OCIParam *param = NULL;
 485         text *colname;
 486         ub4 counter;
 487         ub2 define_type;
 488         ub4 iters;
 489         ub4 colcount;
 490         ub2 dynamic;
 491         dvoid *buf;
 492         sword errstatus;
 493 
 494         switch (mode) {
 495                 case OCI_COMMIT_ON_SUCCESS:
 496                 case OCI_DESCRIBE_ONLY:
 497                 case OCI_DEFAULT:
 498                         /* only these are allowed */
 499 #ifdef HAVE_OCI8_DTRACE
 500                         if (DTRACE_OCI8_EXECUTE_MODE_ENABLED()) {
 501                                 DTRACE_OCI8_EXECUTE_MODE(statement->connection, statement->connection->client_id, statement, mode);
 502                         }
 503 #endif /* HAVE_OCI8_DTRACE */
 504                         break;
 505                 default:
 506                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid execute mode given: %d", mode);
 507                         return 1;
 508                         break;
 509         }
 510         
 511         if (!statement->stmttype) {
 512                 /* get statement type */
 513                 PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement->stmttype, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
 514 
 515                 if (errstatus != OCI_SUCCESS) {
 516                         statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 517                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 518                         return 1;
 519                 } else {
 520                         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 521                 }
 522         }
 523 
 524         if (statement->stmttype == OCI_STMT_SELECT) {
 525                 iters = 0;
 526         } else {
 527                 iters = 1;
 528         }
 529         
 530         if (statement->last_query) { /* Don't execute REFCURSORS or Implicit Result Set handles */
 531 
 532                 if (statement->binds) {
 533                         int result = 0;
 534                         zend_hash_apply_with_argument(statement->binds, (apply_func_arg_t) php_oci_bind_pre_exec, (void *)&result TSRMLS_CC);
 535                         if (result) {
 536                                 return 1;
 537                         }
 538                 }
 539 
 540                 /* execute statement */
 541                 PHP_OCI_CALL_RETURN(errstatus, OCIStmtExecute, (statement->connection->svc, statement->stmt, statement->err, iters, 0, NULL, NULL, mode));
 542 
 543                 if (errstatus != OCI_SUCCESS) {
 544                         statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 545                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 546                         return 1;
 547                 }
 548                 
 549                 if (statement->binds) {
 550                         zend_hash_apply(statement->binds, (apply_func_t) php_oci_bind_post_exec TSRMLS_CC);
 551                 }
 552 
 553                 if (mode & OCI_COMMIT_ON_SUCCESS) {
 554                         /* No need to rollback on disconnect */
 555                         statement->connection->rb_on_disconnect = 0;
 556                 } else if (statement->stmttype != OCI_STMT_SELECT) {
 557                         /* Assume some uncommitted DML occurred */
 558                         statement->connection->rb_on_disconnect = 1;
 559                 }
 560                 /* else for SELECT with OCI_NO_AUTO_COMMIT, leave
 561                  * "rb_on_disconnect" at its previous value.  SELECT can't
 562                  * initiate uncommitted DML. (An AUTONOMOUS_TRANSACTION in
 563                  * invoked PL/SQL must explicitly rollback/commit else the
 564                  * SELECT fails).
 565                  */
 566 
 567                 statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 568         }
 569 
 570         if (statement->stmttype == OCI_STMT_SELECT && statement->executed == 0) {
 571                 /* we only need to do the define step is this very statement is executed the first time! */
 572                 statement->executed = 1;
 573                 
 574                 ALLOC_HASHTABLE(statement->columns);
 575                 zend_hash_init(statement->columns, 13, NULL, php_oci_column_hash_dtor, 0);
 576                 
 577                 counter = 1;
 578 
 579                 /* get number of columns */
 580                 PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *)&colcount, (ub4 *)0, OCI_ATTR_PARAM_COUNT, statement->err));
 581                 
 582                 if (errstatus != OCI_SUCCESS) {
 583                         statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 584                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 585                         return 1;
 586                 }
 587 
 588                 statement->ncolumns = colcount;
 589                 
 590                 for (counter = 1; counter <= colcount; counter++) {
 591                         memset(&column,0,sizeof(php_oci_out_column));
 592                         
 593                         if (zend_hash_index_update(statement->columns, counter, &column, sizeof(php_oci_out_column), (void**) &outcol) == FAILURE) {
 594                                 efree(statement->columns);
 595                                 /* out of memory */
 596                                 return 1;
 597                         }
 598                         
 599                         /* get column */
 600                         PHP_OCI_CALL_RETURN(errstatus, OCIParamGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, statement->err, (dvoid**)&param, counter));
 601                         
 602                         if (errstatus != OCI_SUCCESS) {
 603                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 604                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 605                                 return 1;
 606                         }
 607 
 608                         /* get column datatype */
 609                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_type, (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->err));
 610 
 611                         if (errstatus != OCI_SUCCESS) {
 612                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 613                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 614                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 615                                 return 1;
 616                         }
 617 
 618                         /* get character set form  */
 619                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_form, (ub4 *)0, OCI_ATTR_CHARSET_FORM, statement->err));
 620 
 621                         if (errstatus != OCI_SUCCESS) {
 622                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 623                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 624                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 625                                 return 1;
 626                         }
 627         
 628                         /* get character set id  */
 629                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_id, (ub4 *)0, OCI_ATTR_CHARSET_ID, statement->err));
 630 
 631                         if (errstatus != OCI_SUCCESS) {
 632                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 633                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 634                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 635                                 return 1;
 636                         }
 637         
 638                         /* get size of the column */
 639                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_size, (dvoid *)0, OCI_ATTR_DATA_SIZE, statement->err));
 640                         
 641                         if (errstatus != OCI_SUCCESS) {
 642                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 643                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 644                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 645                                 return 1;
 646                         }
 647 
 648                         outcol->storage_size4 = outcol->data_size;
 649                         outcol->retlen = outcol->data_size;
 650 
 651                         /* get scale of the column */
 652                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->scale, (dvoid *)0, OCI_ATTR_SCALE, statement->err));
 653                         
 654                         if (errstatus != OCI_SUCCESS) {
 655                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 656                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 657                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 658                                 return 1;
 659                         }
 660 
 661                         /* get precision of the column */
 662                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->precision, (dvoid *)0, OCI_ATTR_PRECISION, statement->err));
 663                         
 664                         if (errstatus != OCI_SUCCESS) {
 665                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 666                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 667                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 668                                 return 1;
 669                         }
 670                         
 671                         /* get name of the column */
 672                         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid **)&colname, (ub4 *)&outcol->name_len, (ub4)OCI_ATTR_NAME, statement->err));
 673                         
 674                         if (errstatus != OCI_SUCCESS) {
 675                                 PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 676                                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
 677                                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
 678                                 return 1;
 679                         }
 680                         PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
 681 
 682                         outcol->name = estrndup((char*) colname, outcol->name_len);
 683 
 684                         /* find a user-set define */
 685                         if (statement->defines) {
 686                                 if (zend_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define) == SUCCESS) {
 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 TSRMLS_CC);
 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 TSRMLS_CC);
 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 TSRMLS_DC)
 851 {
 852         return php_oci_statement_fetch(statement, 0 TSRMLS_CC);
 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 TSRMLS_DC)
 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->columns) {
 879                 zend_hash_destroy(statement->columns);
 880                 efree(statement->columns);
 881         }
 882 
 883         if (statement->binds) {
 884                 zend_hash_destroy(statement->binds);
 885                 efree(statement->binds);
 886         }
 887 
 888         if (statement->defines) {
 889                 zend_hash_destroy(statement->defines);
 890                 efree(statement->defines);
 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(void *data, void *result TSRMLS_DC)
 907 {
 908         php_oci_bind *bind = (php_oci_bind *) 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 TSRMLS_CC, 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 TSRMLS_CC, 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 TSRMLS_CC, 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(void *data TSRMLS_DC)
 966 {
 967         php_oci_bind *bind = (php_oci_bind *) 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_STRVAL_P(bind->zval) = erealloc(Z_STRVAL_P(bind->zval), Z_STRLEN_P(bind->zval)+1);
 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;
 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 < bind->array.current_length; i++) {
1001                                         if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
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 < bind->array.current_length; i++) {
1012                                         if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
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 < 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 < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
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 TSRMLS_CC);
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, 1);
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 TSRMLS_CC);
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, 1);
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 < 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 < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
1065                                                 zval_dtor(*entry);
1066                                                 ZVAL_STRINGL(*entry, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length, 1);
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, 1);
1070                                         }
1071                                 }
1072                                 break;
1073                 }
1074         }
1075 
1076         return 0;
1077 }
1078 /* }}} */
1079 
1080 /* {{{ php_oci_bind_by_name()
1081  Bind zval to the given placeholder */
1082 int php_oci_bind_by_name(php_oci_statement *statement, char *name, int name_len, zval *var, long maxlength, ub2 type TSRMLS_DC)
1083 {
1084         php_oci_collection *bind_collection = NULL;
1085         php_oci_descriptor *bind_descriptor = NULL;
1086         php_oci_statement  *bind_statement      = NULL;
1087         dvoid *oci_desc                                 = NULL;
1088         /* dvoid *php_oci_collection               = NULL; */
1089         OCIStmt *oci_stmt                               = NULL;
1090         dvoid *bind_data                                = NULL;
1091         php_oci_bind bind, *old_bind, *bindp;
1092         int mode = OCI_DATA_AT_EXEC;
1093         sb4 value_sz = -1;
1094         sword errstatus;
1095 
1096         switch (type) {
1097                 case SQLT_NTY:
1098                 {
1099                         zval **tmp;
1100                         
1101                         if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
1102                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
1103                                 return 1;
1104                         }
1105 
1106                         PHP_OCI_ZVAL_TO_COLLECTION_EX(*tmp, bind_collection);
1107                         value_sz = sizeof(void*);
1108                         mode = OCI_DEFAULT;
1109                 
1110                         if (!bind_collection->collection) {
1111                                 return 1;
1112                         }
1113                 }
1114                         break;
1115                 case SQLT_BFILEE:
1116                 case SQLT_CFILEE:
1117                 case SQLT_CLOB:
1118                 case SQLT_BLOB:
1119                 case SQLT_RDD:
1120                 {
1121                         zval **tmp;
1122                         
1123                         if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
1124                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
1125                                 return 1;
1126                         }
1127 
1128                         PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, bind_descriptor);
1129 
1130                         value_sz = sizeof(void*);
1131                         
1132                         oci_desc = bind_descriptor->descriptor;
1133                         
1134                         if (!oci_desc) {
1135                                 return 1;
1136                         }
1137                 }
1138                         break;
1139                         
1140                 case SQLT_INT:
1141                 case SQLT_NUM:
1142                 {
1143                         if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
1144                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
1145                                 return 1;
1146                         }
1147                         convert_to_long(var);
1148 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION > 10
1149                         bind_data = (ub8 *)&Z_LVAL_P(var);
1150                         value_sz = sizeof(ub8);
1151 #else
1152                         bind_data = (ub4 *)&Z_LVAL_P(var);
1153                         value_sz = sizeof(ub4);
1154 #endif
1155                         mode = OCI_DEFAULT;
1156                 }
1157                 break;
1158                         
1159                 case SQLT_LBI:
1160                 case SQLT_BIN:
1161                 case SQLT_LNG:
1162                 case SQLT_AFC:
1163                 case SQLT_CHR: /* SQLT_CHR is the default value when type was not specified */
1164                         if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
1165                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
1166                                 return 1;
1167                         }
1168                         if (Z_TYPE_P(var) != IS_NULL) {
1169                                 convert_to_string(var);
1170                         }
1171                         if (maxlength == -1) {
1172                                 value_sz = (Z_TYPE_P(var) == IS_STRING) ? Z_STRLEN_P(var) : 0;
1173                         } else {
1174                                 value_sz = maxlength;
1175                         }
1176                         break;
1177 
1178                 case SQLT_RSET:
1179                         if (Z_TYPE_P(var) != IS_RESOURCE) {
1180                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
1181                                 return 1;
1182                         }
1183                         PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement);
1184                         value_sz = sizeof(void*);
1185 
1186                         oci_stmt = bind_statement->stmt;
1187 
1188                         if (!oci_stmt) {
1189                                 return 1;
1190                         }
1191                         break;
1192 
1193 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12
1194                 case SQLT_BOL:
1195                         if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
1196                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
1197                                 return 1;
1198                         }
1199                         convert_to_boolean(var);
1200                         bind_data = (int *)&Z_LVAL_P(var);
1201                         value_sz = sizeof(int);
1202 
1203                         mode = OCI_DEFAULT;
1204                         break;
1205 #endif
1206 
1207                 default:
1208                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %d", (int)type);
1209                         return 1;
1210                         break;
1211         }
1212         
1213         if (value_sz == 0) {
1214                 value_sz = 1;
1215         }
1216         
1217         if (!statement->binds) {
1218                 ALLOC_HASHTABLE(statement->binds);
1219                 zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
1220         }
1221 
1222         memset((void*)&bind,0,sizeof(php_oci_bind));
1223         if (zend_hash_find(statement->binds, name, name_len + 1, (void **)&old_bind) == SUCCESS) {
1224                 bindp = old_bind;
1225                 if (bindp->zval) {
1226                         zval_ptr_dtor(&bindp->zval);
1227                 }
1228         } else {
1229                 zend_hash_update(statement->binds, name, name_len + 1, &bind, sizeof(php_oci_bind), (void **)&bindp);
1230         }
1231         
1232         bindp->descriptor = oci_desc;
1233         bindp->statement = oci_stmt;
1234         bindp->parent_statement = statement;
1235         bindp->zval = var;
1236         bindp->type = type;
1237         zval_add_ref(&var);
1238         
1239         PHP_OCI_CALL_RETURN(errstatus,
1240                 OCIBindByName,
1241                 (
1242                         statement->stmt,                                 /* statement handle */
1243                         (OCIBind **)&bindp->bind,                /* bind hdl (will alloc) */
1244                         statement->err,                                  /* error handle */
1245                         (text*) name,                                    /* placeholder name */                                 
1246                         name_len,                                                /* placeholder length */
1247                         (dvoid *)bind_data,                              /* in/out data */
1248                         value_sz, /* PHP_OCI_MAX_DATA_SIZE, */ /* max size of input/output data */
1249                         type,                                                    /* in/out data type */
1250                         (dvoid *)&bindp->indicator,              /* indicator (ignored) */
1251                         (ub2 *)0,                                                /* size array (ignored) */
1252                         (ub2 *)&bindp->retcode,                  /* return code (ignored) */
1253                         (ub4)0,                                                  /* maxarr_len (PL/SQL only?) */
1254                         (ub4 *)0,                                                /* actual array size (PL/SQL only?) */
1255                         mode                                                     /* mode */
1256                 )
1257         );
1258 
1259         if (errstatus != OCI_SUCCESS) {
1260                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
1261                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1262                 return 1;
1263         }
1264 
1265         if (mode == OCI_DATA_AT_EXEC) {
1266                 PHP_OCI_CALL_RETURN(errstatus, OCIBindDynamic,
1267                                 (
1268                                  bindp->bind,
1269                                  statement->err,
1270                                  (dvoid *)bindp,
1271                                  php_oci_bind_in_callback,
1272                                  (dvoid *)bindp,
1273                                  php_oci_bind_out_callback
1274                                 )
1275                 );
1276 
1277                 if (errstatus != OCI_SUCCESS) {
1278                         statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
1279                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1280                         return 1;
1281                 }
1282         }
1283 
1284         if (type == SQLT_NTY) {
1285                 /* Bind object */
1286                 PHP_OCI_CALL_RETURN(errstatus, OCIBindObject,
1287                                 (
1288                                  bindp->bind,
1289                                  statement->err,
1290                                  bind_collection->tdo,
1291                                  (dvoid **) &(bind_collection->collection),
1292                                  (ub4 *) 0,
1293                                  (dvoid **) 0,
1294                                  (ub4 *) 0
1295                                 )
1296                 );
1297                 
1298                 if (errstatus) {
1299                         statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
1300                         PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1301                         return 1;
1302                 }
1303         }
1304         
1305         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1306         return 0;
1307 }
1308 /* }}} */
1309 
1310 /* {{{ php_oci_bind_in_callback()
1311  Callback used when binding LOBs and VARCHARs */
1312 sb4 php_oci_bind_in_callback(
1313                                         dvoid *ictxp,     /* context pointer */
1314                                         OCIBind *bindp,   /* bind handle */
1315                                         ub4 iter,                 /* 0-based execute iteration value */
1316                                         ub4 index,                /* index of current array for PL/SQL or row index for SQL */
1317                                         dvoid **bufpp,    /* pointer to data */
1318                                         ub4 *alenp,               /* size after value/piece has been read */
1319                                         ub1 *piecep,      /* which piece */
1320                                         dvoid **indpp)    /* indicator value */
1321 {
1322         php_oci_bind *phpbind;
1323         zval *val;
1324         TSRMLS_FETCH();
1325 
1326         if (!(phpbind=(php_oci_bind *)ictxp) || !(val = phpbind->zval)) {
1327                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
1328                 return OCI_ERROR;
1329         }
1330 
1331         if (ZVAL_IS_NULL(val)) {
1332                 /* we're going to insert a NULL column */
1333                 phpbind->indicator = -1;
1334                 *bufpp = 0;
1335                 *alenp = -1;
1336                 *indpp = (dvoid *)&phpbind->indicator;
1337         } else  if ((phpbind->descriptor == 0) && (phpbind->statement == 0)) {
1338                 /* "normal string bind */
1339                 convert_to_string(val);
1340 
1341                 *bufpp = Z_STRVAL_P(val);
1342                 *alenp = Z_STRLEN_P(val);
1343                 *indpp = (dvoid *)&phpbind->indicator;
1344         } else if (phpbind->statement != 0) {
1345                 /* RSET */
1346                 *bufpp = phpbind->statement;
1347                 *alenp = -1;            /* seems to be allright */
1348                 *indpp = (dvoid *)&phpbind->indicator;
1349         } else {
1350                 /* descriptor bind */
1351                 *bufpp = phpbind->descriptor;
1352                 *alenp = -1;            /* seems to be allright */
1353                 *indpp = (dvoid *)&phpbind->indicator;
1354         }
1355 
1356         *piecep = OCI_ONE_PIECE; /* pass all data in one go */
1357 
1358         return OCI_CONTINUE;
1359 }
1360 /* }}} */
1361 
1362 /* {{{ php_oci_bind_out_callback()
1363  Callback used when binding LOBs and VARCHARs */
1364 sb4 php_oci_bind_out_callback(
1365                                         dvoid *octxp,      /* context pointer */
1366                                         OCIBind *bindp,    /* bind handle */
1367                                         ub4 iter,                  /* 0-based execute iteration value */
1368                                         ub4 index,                 /* index of current array for PL/SQL or row index for SQL */
1369                                         dvoid **bufpp,     /* pointer to data */
1370                                         ub4 **alenpp,      /* size after value/piece has been read */
1371                                         ub1 *piecep,       /* which piece */
1372                                         dvoid **indpp,     /* indicator value */
1373                                         ub2 **rcodepp)     /* return code */
1374 {
1375         php_oci_bind *phpbind;
1376         zval *val;
1377         sb4 retval = OCI_ERROR;
1378         TSRMLS_FETCH();
1379 
1380         if (!(phpbind=(php_oci_bind *)octxp) || !(val = phpbind->zval)) {
1381                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
1382                 return retval;
1383         }
1384 
1385         if (Z_TYPE_P(val) == IS_RESOURCE) {
1386                 /* Processing for ref-cursor out binds */
1387                 if (phpbind->statement != NULL) {
1388                         *bufpp = phpbind->statement;
1389                         *alenpp = &phpbind->dummy_len;
1390                         *piecep = OCI_ONE_PIECE;
1391                         *rcodepp = &phpbind->retcode;
1392                         *indpp = &phpbind->indicator;
1393                 }
1394                 retval = OCI_CONTINUE;
1395         } else if (Z_TYPE_P(val) == IS_OBJECT) {
1396                 zval **tmp;
1397                 php_oci_descriptor *desc;
1398 
1399                 if (!phpbind->descriptor) {
1400                         return OCI_ERROR;
1401                 }
1402 
1403                 /* Do not use the cached lob size if the descriptor is an
1404                  * out-bind as the contents would have been changed for in/out
1405                  * binds (Bug #46994).
1406                  */
1407                 if (zend_hash_find(Z_OBJPROP_P(val), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
1408                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find object outbind descriptor property");
1409                         return OCI_ERROR;
1410                 }
1411                 PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, desc);
1412                 desc->lob_size = -1;    /* force OCI8 to update cached size */
1413 
1414                 *alenpp = &phpbind->dummy_len;
1415                 *bufpp = phpbind->descriptor;
1416                 *piecep = OCI_ONE_PIECE;
1417                 *rcodepp = &phpbind->retcode;
1418                 *indpp = &phpbind->indicator;
1419                 retval = OCI_CONTINUE;
1420         } else {
1421                 convert_to_string(val);
1422                 zval_dtor(val);
1423                 
1424                 Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
1425                 Z_STRVAL_P(val) = ecalloc(1, Z_STRLEN_P(phpbind->zval) + 1);
1426                 
1427                 /* XXX we assume that zend-zval len has 4 bytes */
1428                 *alenpp = (ub4*) &Z_STRLEN_P(phpbind->zval);
1429                 *bufpp = Z_STRVAL_P(phpbind->zval);
1430                 *piecep = OCI_ONE_PIECE;
1431                 *rcodepp = &phpbind->retcode;
1432                 *indpp = &phpbind->indicator;
1433                 retval = OCI_CONTINUE;
1434         }
1435 
1436         return retval;
1437 }
1438 /* }}} */
1439 
1440 /* {{{ php_oci_statement_get_column_helper()
1441  Helper function to get column by name and index */
1442 php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAMETERS, int need_data)
1443 {
1444         zval *z_statement, *column_index;
1445         php_oci_statement *statement;
1446         php_oci_out_column *column;
1447 
1448         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_statement, &column_index) == FAILURE) {
1449                 return NULL;
1450         }
1451 
1452         statement = (php_oci_statement *) zend_fetch_resource(&z_statement TSRMLS_CC, -1, "oci8 statement", NULL, 1, le_statement);
1453 
1454         if (!statement) {
1455                 return NULL;
1456         }
1457 
1458         if (need_data && !statement->has_data) {
1459                 return NULL;
1460         }
1461         
1462         if (Z_TYPE_P(column_index) == IS_STRING) {
1463                 column = php_oci_statement_get_column(statement, -1, Z_STRVAL_P(column_index), Z_STRLEN_P(column_index) TSRMLS_CC);
1464                 if (!column) {
1465                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column name \"%s\"", Z_STRVAL_P(column_index));
1466                         return NULL;
1467                 }
1468         } else {
1469                 zval tmp;
1470                 /* NB: for PHP4 compat only, it should be using 'Z' instead */
1471                 tmp = *column_index;
1472                 zval_copy_ctor(&tmp);
1473                 convert_to_long(&tmp);
1474                 column = php_oci_statement_get_column(statement, Z_LVAL(tmp), NULL, 0 TSRMLS_CC);
1475                 if (!column) {
1476                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column index \"%ld\"", Z_LVAL(tmp));
1477                         zval_dtor(&tmp);
1478                         return NULL;
1479                 }
1480                 zval_dtor(&tmp);
1481         }
1482         return column;
1483 }
1484 /* }}} */
1485 
1486 /* {{{ php_oci_statement_get_type()
1487  Return type of the statement */
1488 int php_oci_statement_get_type(php_oci_statement *statement, ub2 *type TSRMLS_DC)
1489 {
1490         ub2 statement_type;
1491         sword errstatus;
1492         
1493         *type = 0;
1494         
1495         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement_type, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
1496 
1497         if (errstatus != OCI_SUCCESS) {
1498                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
1499                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1500                 return 1;
1501         }
1502         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1503         *type = statement_type;
1504 
1505         return 0;
1506 }
1507 /* }}} */
1508 
1509 /* {{{ php_oci_statement_get_numrows()
1510  Get the number of rows fetched to the clientside (NOT the number of rows in the result set) */
1511 int php_oci_statement_get_numrows(php_oci_statement *statement, ub4 *numrows TSRMLS_DC)
1512 {
1513         ub4 statement_numrows;
1514         sword errstatus;
1515         
1516         *numrows = 0;
1517         
1518         PHP_OCI_CALL_RETURN(errstatus, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub4 *)&statement_numrows, (ub4 *)0, OCI_ATTR_ROW_COUNT, statement->err));
1519 
1520         if (errstatus != OCI_SUCCESS) {
1521                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
1522                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1523                 return 1;
1524         }
1525         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1526         *numrows = statement_numrows;
1527 
1528         return 0;
1529 }
1530 /* }}} */
1531 
1532 /* {{{ php_oci_bind_array_by_name()
1533  Bind arrays to PL/SQL types */
1534 int php_oci_bind_array_by_name(php_oci_statement *statement, char *name, int name_len, zval *var, long max_table_length, long maxlength, long type TSRMLS_DC)
1535 {
1536         php_oci_bind *bind, *bindp;
1537         sword errstatus;
1538 
1539         convert_to_array(var);
1540 
1541         if (maxlength < -1) {
1542                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid max length value (%ld)", maxlength);
1543                 return 1;
1544         }
1545         
1546         switch(type) {
1547                 case SQLT_NUM:
1548                 case SQLT_INT:
1549                 case SQLT_LNG:
1550                         bind = php_oci_bind_array_helper_number(var, max_table_length TSRMLS_CC);
1551                         break;
1552 
1553                 case SQLT_FLT:
1554                         bind = php_oci_bind_array_helper_double(var, max_table_length TSRMLS_CC);
1555                         break;
1556                         
1557                 case SQLT_AFC:
1558                 case SQLT_CHR:
1559                 case SQLT_VCS:
1560                 case SQLT_AVC:
1561                 case SQLT_STR:
1562                 case SQLT_LVC:
1563                         if (maxlength == -1 && zend_hash_num_elements(Z_ARRVAL_P(var)) == 0) {
1564                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must provide max length value for empty arrays");
1565                                 return 1;
1566                         }
1567                         bind = php_oci_bind_array_helper_string(var, max_table_length, maxlength TSRMLS_CC);
1568                         break;
1569                 case SQLT_ODT:
1570                         bind = php_oci_bind_array_helper_date(var, max_table_length, statement->connection TSRMLS_CC);
1571                         break;
1572                 default:
1573                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %ld", type);
1574                         return 1;
1575                         break;
1576         }
1577 
1578         if (bind == NULL) {
1579                 /* failed to generate bind struct */
1580                 return 1;
1581         }
1582         
1583         if (!statement->binds) {
1584                 ALLOC_HASHTABLE(statement->binds);
1585                 zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
1586         }
1587 
1588         zend_hash_update(statement->binds, name, name_len + 1, bind, sizeof(php_oci_bind), (void **)&bindp);
1589 
1590         bindp->descriptor = NULL;
1591         bindp->statement = NULL;
1592         bindp->parent_statement = statement;
1593         bindp->bind = NULL;
1594         bindp->zval = var;
1595         bindp->array.type = type;
1596         bindp->indicator = 0;           /* not used for array binds */
1597         bindp->type = 0;                        /* not used for array binds */
1598 
1599         zval_add_ref(&var);
1600 
1601         PHP_OCI_CALL_RETURN(errstatus,
1602                                                         OCIBindByName,
1603                                                         (
1604                                                                 statement->stmt,
1605                                                                 (OCIBind **)&bindp->bind,
1606                                                                 statement->err,
1607                                                                 (text *)name,
1608                                                                 name_len,
1609                                                                 (dvoid *) bindp->array.elements,
1610                                                                 (sb4) bind->array.max_length,
1611                                                                 (ub2)type,
1612                                                                 (dvoid *)bindp->array.indicators,
1613                                                                 (ub2 *)bind->array.element_lengths,
1614                                                                 (ub2 *)0, /* bindp->array.retcodes, */
1615                                                                 (ub4) max_table_length,
1616                                                                 (ub4 *) &(bindp->array.current_length),
1617                                                                 (ub4) OCI_DEFAULT
1618                                                         )
1619                                                 );
1620         
1621                 
1622         if (errstatus != OCI_SUCCESS) {
1623                 efree(bind);
1624                 statement->errcode = php_oci_error(statement->err, errstatus TSRMLS_CC);
1625                 PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
1626                 return 1;
1627         }
1628         statement->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1629         efree(bind);
1630         return 0;
1631 }
1632 /* }}} */
1633 
1634 /* {{{ php_oci_bind_array_helper_string()
1635  Bind arrays to PL/SQL types */
1636 php_oci_bind *php_oci_bind_array_helper_string(zval *var, long max_table_length, long maxlength TSRMLS_DC)
1637 {
1638         php_oci_bind *bind;
1639         ub4 i;
1640         HashTable *hash;
1641         zval **entry;
1642 
1643         hash = HASH_OF(var);
1644 
1645         if (maxlength == -1) {
1646                 zend_hash_internal_pointer_reset(hash);
1647                 while (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE) {
1648                         convert_to_string_ex(entry);
1649                         if (Z_STRLEN_PP(entry) > maxlength) {
1650                                 maxlength = Z_STRLEN_PP(entry) + 1;
1651                         }
1652                         zend_hash_move_forward(hash);
1653                 }
1654         }
1655         
1656         bind = emalloc(sizeof(php_oci_bind));
1657         bind->array.elements            = (text *)safe_emalloc(max_table_length * (maxlength + 1), sizeof(text), 0);
1658         memset(bind->array.elements, 0, max_table_length * (maxlength + 1) * sizeof(text));
1659         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1660         bind->array.old_length          = bind->array.current_length;
1661         bind->array.max_length          = maxlength;
1662         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1663         memset(bind->array.element_lengths, 0, max_table_length*sizeof(ub2));
1664         bind->array.indicators          = safe_emalloc(max_table_length, sizeof(sb2), 0);
1665         memset(bind->array.indicators, 0, max_table_length*sizeof(sb2));
1666         
1667         zend_hash_internal_pointer_reset(hash);
1668         
1669         for (i = 0; i < bind->array.current_length; i++) {
1670                 if (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE) {
1671                         convert_to_string_ex(entry);
1672                         bind->array.element_lengths[i] = Z_STRLEN_PP(entry);
1673                         if (Z_STRLEN_PP(entry) == 0) {
1674                                 bind->array.indicators[i] = -1;
1675                         }
1676                         zend_hash_move_forward(hash);
1677                 } else {
1678                         break;
1679                 }
1680         }
1681 
1682         zend_hash_internal_pointer_reset(hash);
1683         for (i = 0; i < max_table_length; i++) {
1684                 if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
1685                         int element_length;
1686                         
1687                         convert_to_string_ex(entry);
1688                         element_length = (maxlength > Z_STRLEN_PP(entry)) ? Z_STRLEN_PP(entry) : maxlength;
1689                         
1690                         memcpy((text *)bind->array.elements + i*maxlength, Z_STRVAL_PP(entry), element_length);
1691                         ((text *)bind->array.elements)[i*maxlength + element_length] = '\0';
1692                         
1693                         zend_hash_move_forward(hash);
1694                 } else {
1695                         ((text *)bind->array.elements)[i*maxlength] = '\0';
1696                 }
1697         }
1698         zend_hash_internal_pointer_reset(hash);
1699 
1700         return bind;
1701 }
1702 /* }}} */
1703 
1704 /* {{{ php_oci_bind_array_helper_number()
1705  Bind arrays to PL/SQL types */
1706 php_oci_bind *php_oci_bind_array_helper_number(zval *var, long max_table_length TSRMLS_DC)
1707 {
1708         php_oci_bind *bind;
1709         ub4 i;
1710         HashTable *hash;
1711         zval **entry;
1712 
1713         hash = HASH_OF(var);
1714 
1715         bind = emalloc(sizeof(php_oci_bind));
1716         bind->array.elements            = (ub4 *)safe_emalloc(max_table_length, sizeof(ub4), 0);
1717         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1718         bind->array.old_length          = bind->array.current_length;
1719         bind->array.max_length          = sizeof(ub4);
1720         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1721         memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
1722         bind->array.indicators          = NULL;
1723         
1724         zend_hash_internal_pointer_reset(hash);
1725         for (i = 0; i < max_table_length; i++) {
1726                 if (i < bind->array.current_length) {
1727                         bind->array.element_lengths[i] = sizeof(ub4);
1728                 }
1729                 if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
1730                         convert_to_long_ex(entry);
1731                         ((ub4 *)bind->array.elements)[i] = (ub4) Z_LVAL_PP(entry);
1732                         zend_hash_move_forward(hash);
1733                 } else {
1734                         ((ub4 *)bind->array.elements)[i] = 0;
1735                 }
1736         }
1737         zend_hash_internal_pointer_reset(hash);
1738 
1739         return bind;
1740 }
1741 /* }}} */
1742 
1743 /* {{{ php_oci_bind_array_helper_double()
1744  Bind arrays to PL/SQL types */
1745 php_oci_bind *php_oci_bind_array_helper_double(zval *var, long max_table_length TSRMLS_DC)
1746 {
1747         php_oci_bind *bind;
1748         ub4 i;
1749         HashTable *hash;
1750         zval **entry;
1751 
1752         hash = HASH_OF(var);
1753 
1754         bind = emalloc(sizeof(php_oci_bind));
1755         bind->array.elements            = (double *)safe_emalloc(max_table_length, sizeof(double), 0);
1756         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1757         bind->array.old_length          = bind->array.current_length;
1758         bind->array.max_length          = sizeof(double);
1759         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1760         memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
1761         bind->array.indicators          = NULL;
1762         
1763         zend_hash_internal_pointer_reset(hash);
1764         for (i = 0; i < max_table_length; i++) {
1765                 if (i < bind->array.current_length) {
1766                         bind->array.element_lengths[i] = sizeof(double);
1767                 }
1768                 if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
1769                         convert_to_double_ex(entry);
1770                         ((double *)bind->array.elements)[i] = (double) Z_DVAL_PP(entry);
1771                         zend_hash_move_forward(hash);
1772                 } else {
1773                         ((double *)bind->array.elements)[i] = 0;
1774                 }
1775         }
1776         zend_hash_internal_pointer_reset(hash);
1777 
1778         return bind;
1779 }
1780 /* }}} */
1781 
1782 /* {{{ php_oci_bind_array_helper_date()
1783  Bind arrays to PL/SQL types */
1784 php_oci_bind *php_oci_bind_array_helper_date(zval *var, long max_table_length, php_oci_connection *connection TSRMLS_DC)
1785 {
1786         php_oci_bind *bind;
1787         ub4 i;
1788         HashTable *hash;
1789         zval **entry;
1790         sword errstatus;
1791 
1792         hash = HASH_OF(var);
1793 
1794         bind = emalloc(sizeof(php_oci_bind));
1795         bind->array.elements            = (OCIDate *)safe_emalloc(max_table_length, sizeof(OCIDate), 0);
1796         bind->array.current_length      = zend_hash_num_elements(Z_ARRVAL_P(var));
1797         bind->array.old_length          = bind->array.current_length;
1798         bind->array.max_length          = sizeof(OCIDate);
1799         bind->array.element_lengths     = safe_emalloc(max_table_length, sizeof(ub2), 0);
1800         memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
1801         bind->array.indicators          = NULL;
1802 
1803         zend_hash_internal_pointer_reset(hash);
1804         for (i = 0; i < max_table_length; i++) {
1805                 OCIDate oci_date;
1806                 if (i < bind->array.current_length) {
1807                         bind->array.element_lengths[i] = sizeof(OCIDate);
1808                 }
1809                 if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
1810                         
1811                         convert_to_string_ex(entry);
1812                         PHP_OCI_CALL_RETURN(errstatus, OCIDateFromText, (connection->err, (CONST text *)Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), NULL, 0, NULL, 0, &oci_date));
1813 
1814                         if (errstatus != OCI_SUCCESS) {
1815                                 /* failed to convert string to date */
1816                                 efree(bind->array.element_lengths);
1817                                 efree(bind->array.elements);
1818                                 efree(bind);
1819                                 connection->errcode = php_oci_error(connection->err, errstatus TSRMLS_CC);
1820                                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
1821                                 return NULL;
1822                         }
1823                         
1824                         ((OCIDate *)bind->array.elements)[i] = oci_date;
1825                         zend_hash_move_forward(hash);
1826                 } else {
1827                         PHP_OCI_CALL_RETURN(errstatus, OCIDateFromText, (connection->err, (CONST text *)"01-JAN-00", sizeof("01-JAN-00")-1, NULL, 0, NULL, 0, &oci_date));
1828 
1829                         if (errstatus != OCI_SUCCESS) {
1830                                 /* failed to convert string to date */
1831                                 efree(bind->array.element_lengths);
1832                                 efree(bind->array.elements);
1833                                 efree(bind);
1834                                 connection->errcode = php_oci_error(connection->err, errstatus TSRMLS_CC);
1835                                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
1836                                 return NULL;
1837                         }
1838         
1839                         ((OCIDate *)bind->array.elements)[i] = oci_date;
1840                 }
1841                 connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
1842         }
1843         zend_hash_internal_pointer_reset(hash);
1844 
1845         return bind;
1846 }
1847 /* }}} */
1848 
1849 #endif /* HAVE_OCI8 */
1850 
1851 /*
1852  * Local variables:
1853  * tab-width: 4
1854  * c-basic-offset: 4
1855  * End:
1856  * vim600: noet sw=4 ts=4 fdm=marker
1857  * vim<600: noet sw=4 ts=4
1858  */

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