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