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