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