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