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