xref: /PHP-5.5/ext/oci8/oci8_statement.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 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**)&param, 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