xref: /PHP-5.3/ext/interbase/ibase_query.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 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: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl>              |
16    +----------------------------------------------------------------------+
17  */
18 
19 /* $Id$ */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "php.h"
26 #include "php_ini.h"
27 
28 #if HAVE_IBASE
29 
30 #include "ext/standard/php_standard.h"
31 #include "php_interbase.h"
32 #include "php_ibase_includes.h"
33 
34 #define ISC_LONG_MIN 	INT_MIN
35 #define ISC_LONG_MAX 	INT_MAX
36 
37 #define QUERY_RESULT	1
38 #define EXECUTE_RESULT	2
39 
40 #define FETCH_ROW		1
41 #define FETCH_ARRAY		2
42 
43 typedef struct {
44 	ISC_ARRAY_DESC ar_desc;
45 	ISC_LONG ar_size; /* size of entire array in bytes */
46 	unsigned short el_type, el_size;
47 } ibase_array;
48 
49 typedef struct {
50 	ibase_db_link *link;
51 	ibase_trans *trans;
52 	struct _ib_query *query;
53 	isc_stmt_handle stmt;
54 	unsigned short type;
55 	unsigned char has_more_rows, statement_type;
56 	XSQLDA *out_sqlda;
57 	ibase_array out_array[1]; /* last member */
58 } ibase_result;
59 
60 typedef struct _ib_query {
61 	ibase_db_link *link;
62 	ibase_trans *trans;
63 	ibase_result *result;
64 	int result_res_id;
65 	isc_stmt_handle stmt;
66 	XSQLDA *in_sqlda, *out_sqlda;
67 	ibase_array *in_array, *out_array;
68 	unsigned short in_array_cnt, out_array_cnt;
69 	unsigned short dialect;
70 	char statement_type;
71 	char *query;
72 	long trans_res_id;
73 } ibase_query;
74 
75 typedef struct {
76 	unsigned short vary_length;
77 	char vary_string[1];
78 } IBVARY;
79 
80 /* sql variables union
81  * used for convert and binding input variables
82  */
83 typedef struct {
84 	union {
85 		short sval;
86 		float fval;
87 		ISC_LONG lval;
88 		ISC_QUAD qval;
89 		ISC_TIMESTAMP tsval;
90 		ISC_DATE dtval;
91 		ISC_TIME tmval;
92 	} val;
93 	short sqlind;
94 } BIND_BUF;
95 
96 static int le_result, le_query;
97 
98 #define LE_RESULT "Firebird/InterBase result"
99 #define LE_QUERY "Firebird/InterBase query"
100 
_php_ibase_free_xsqlda(XSQLDA * sqlda)101 static void _php_ibase_free_xsqlda(XSQLDA *sqlda) /* {{{ */
102 {
103 	int i;
104 	XSQLVAR *var;
105 
106 	IBDEBUG("Free XSQLDA?");
107 	if (sqlda) {
108 		IBDEBUG("Freeing XSQLDA...");
109 		var = sqlda->sqlvar;
110 		for (i = 0; i < sqlda->sqld; i++, var++) {
111 			efree(var->sqldata);
112 			if (var->sqlind) {
113 				efree(var->sqlind);
114 			}
115 		}
116 		efree(sqlda);
117 	}
118 }
119 /* }}} */
120 
_php_ibase_free_stmt_handle(ibase_db_link * link,isc_stmt_handle stmt TSRMLS_DC)121 static void _php_ibase_free_stmt_handle(ibase_db_link *link, isc_stmt_handle stmt TSRMLS_DC) /* {{{ */
122 {
123 	static char info[] = { isc_info_base_level, isc_info_end };
124 
125 	if (stmt) {
126 		char res_buf[8];
127 		IBDEBUG("Dropping statement handle (free_stmt_handle)...");
128 		/* Only free statement if db-connection is still open */
129 		if (SUCCESS == isc_database_info(IB_STATUS, &link->handle,
130 							sizeof(info), info, sizeof(res_buf), res_buf)) {
131 			if (isc_dsql_free_statement(IB_STATUS, &stmt, DSQL_drop)) {
132 				_php_ibase_error(TSRMLS_C);
133 			}
134 		}
135 	}
136 }
137 /* }}} */
138 
_php_ibase_free_result(zend_rsrc_list_entry * rsrc TSRMLS_DC)139 static void _php_ibase_free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
140 {
141 	ibase_result *ib_result = (ibase_result *) rsrc->ptr;
142 
143 	IBDEBUG("Freeing result by dtor...");
144 	if (ib_result) {
145 		_php_ibase_free_xsqlda(ib_result->out_sqlda);
146 		if (ib_result->query != NULL) {
147 			IBDEBUG("query still valid; don't drop statement handle");
148 			ib_result->query->result = NULL;	/* Indicate to query, that result is released */
149 		} else {
150 			_php_ibase_free_stmt_handle(ib_result->link, ib_result->stmt TSRMLS_CC);
151 		}
152 		efree(ib_result);
153 	}
154 }
155 /* }}} */
156 
_php_ibase_free_query(ibase_query * ib_query TSRMLS_DC)157 static void _php_ibase_free_query(ibase_query *ib_query TSRMLS_DC) /* {{{ */
158 {
159 	IBDEBUG("Freeing query...");
160 
161 	if (ib_query->in_sqlda) {
162 		efree(ib_query->in_sqlda);
163 	}
164 	if (ib_query->out_sqlda) {
165 		efree(ib_query->out_sqlda);
166 	}
167 	if (ib_query->result != NULL) {
168 		IBDEBUG("result still valid; don't drop statement handle");
169 		ib_query->result->query = NULL;	/* Indicate to result, that query is released */
170 	} else {
171 		_php_ibase_free_stmt_handle(ib_query->link, ib_query->stmt TSRMLS_CC);
172 	}
173 	if (ib_query->in_array) {
174 		efree(ib_query->in_array);
175 	}
176 	if (ib_query->out_array) {
177 		efree(ib_query->out_array);
178 	}
179 	if (ib_query->query) {
180 		efree(ib_query->query);
181 	}
182 }
183 /* }}} */
184 
php_ibase_free_query_rsrc(zend_rsrc_list_entry * rsrc TSRMLS_DC)185 static void php_ibase_free_query_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
186 {
187 	ibase_query *ib_query = (ibase_query *)rsrc->ptr;
188 
189 	if (ib_query != NULL) {
190 		IBDEBUG("Preparing to free query by dtor...");
191 		_php_ibase_free_query(ib_query TSRMLS_CC);
192 		efree(ib_query);
193 	}
194 }
195 /* }}} */
196 
php_ibase_query_minit(INIT_FUNC_ARGS)197 void php_ibase_query_minit(INIT_FUNC_ARGS) /* {{{ */
198 {
199 	le_result = zend_register_list_destructors_ex(_php_ibase_free_result, NULL,
200 	    "interbase result", module_number);
201 	le_query = zend_register_list_destructors_ex(php_ibase_free_query_rsrc, NULL,
202 	    "interbase query", module_number);
203 }
204 /* }}} */
205 
_php_ibase_alloc_array(ibase_array ** ib_arrayp,XSQLDA * sqlda,isc_db_handle link,isc_tr_handle trans,unsigned short * array_cnt TSRMLS_DC)206 static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ */
207 	isc_db_handle link, isc_tr_handle trans, unsigned short *array_cnt TSRMLS_DC)
208 {
209 	unsigned short i, n;
210 	ibase_array *ar;
211 
212 	/* first check if we have any arrays at all */
213 	for (i = *array_cnt = 0; i < sqlda->sqld; ++i) {
214 		if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_ARRAY) {
215 			++*array_cnt;
216 		}
217 	}
218 	if (! *array_cnt) return SUCCESS;
219 
220 	ar = safe_emalloc(sizeof(ibase_array), *array_cnt, 0);
221 
222 	for (i = n = 0; i < sqlda->sqld; ++i) {
223 		unsigned short dim;
224 		unsigned long ar_size = 1;
225 		XSQLVAR *var = &sqlda->sqlvar[i];
226 
227 		if ((var->sqltype & ~1) == SQL_ARRAY) {
228 			ibase_array *a = &ar[n++];
229 			ISC_ARRAY_DESC *ar_desc = &a->ar_desc;
230 
231 			if (isc_array_lookup_bounds(IB_STATUS, &link, &trans, var->relname,
232 					var->sqlname, ar_desc)) {
233 				_php_ibase_error(TSRMLS_C);
234 				efree(ar);
235 				return FAILURE;
236 			}
237 
238 			switch (ar_desc->array_desc_dtype) {
239 				case blr_text:
240 				case blr_text2:
241 					a->el_type = SQL_TEXT;
242 					a->el_size = ar_desc->array_desc_length;
243 					break;
244 				case blr_short:
245 					a->el_type = SQL_SHORT;
246 					a->el_size = sizeof(short);
247 					break;
248 				case blr_long:
249 					a->el_type = SQL_LONG;
250 					a->el_size = sizeof(ISC_LONG);
251 					break;
252 				case blr_float:
253 					a->el_type = SQL_FLOAT;
254 					a->el_size = sizeof(float);
255 					break;
256 				case blr_double:
257 					a->el_type = SQL_DOUBLE;
258 					a->el_size = sizeof(double);
259 					break;
260 				case blr_int64:
261 					a->el_type = SQL_INT64;
262 					a->el_size = sizeof(ISC_INT64);
263 					break;
264 				case blr_timestamp:
265 					a->el_type = SQL_TIMESTAMP;
266 					a->el_size = sizeof(ISC_TIMESTAMP);
267 					break;
268 				case blr_sql_date:
269 					a->el_type = SQL_TYPE_DATE;
270 					a->el_size = sizeof(ISC_DATE);
271 					break;
272 				case blr_sql_time:
273 					a->el_type = SQL_TYPE_TIME;
274 					a->el_size = sizeof(ISC_TIME);
275 					break;
276 				case blr_varying:
277 				case blr_varying2:
278 					/**
279 					 * IB has a strange way of handling VARCHAR arrays. It doesn't store
280 					 * the length in the first short, as with VARCHAR fields. It does,
281 					 * however, expect the extra short to be allocated for each element.
282 					 */
283 					a->el_type = SQL_TEXT;
284 					a->el_size = ar_desc->array_desc_length + sizeof(short);
285 					break;
286 				case blr_quad:
287 				case blr_blob_id:
288 				case blr_cstring:
289 				case blr_cstring2:
290 					/**
291 					 * These types are mentioned as array types in the manual, but I
292 					 * wouldn't know how to create an array field with any of these
293 					 * types. I assume these types are not applicable to arrays, and
294 					 * were mentioned erroneously.
295 					 */
296 				default:
297 					_php_ibase_module_error("Unsupported array type %d in relation '%s' column '%s'"
298 						TSRMLS_CC, ar_desc->array_desc_dtype, var->relname, var->sqlname);
299 					efree(ar);
300 					return FAILURE;
301 			} /* switch array_desc_type */
302 
303 			/* calculate elements count */
304 			for (dim = 0; dim < ar_desc->array_desc_dimensions; dim++) {
305 				ar_size *= 1 + ar_desc->array_desc_bounds[dim].array_bound_upper
306 					-ar_desc->array_desc_bounds[dim].array_bound_lower;
307 			}
308 			a->ar_size = a->el_size * ar_size;
309 		} /* if SQL_ARRAY */
310 	} /* for column */
311 	*ib_arrayp = ar;
312 	return SUCCESS;
313 }
314 /* }}} */
315 
316 /* allocate and prepare query */
_php_ibase_alloc_query(ibase_query * ib_query,ibase_db_link * link,ibase_trans * trans,char * query,unsigned short dialect,int trans_res_id TSRMLS_DC)317 static int _php_ibase_alloc_query(ibase_query *ib_query, ibase_db_link *link, /* {{{ */
318 	ibase_trans *trans, char *query, unsigned short dialect, int trans_res_id TSRMLS_DC)
319 {
320 	static char info_type[] = {isc_info_sql_stmt_type};
321 	char result[8];
322 
323 	/* Return FAILURE, if querystring is empty */
324 	if (*query == '\0') {
325 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Querystring empty.");
326 		return FAILURE;
327 	}
328 
329 	ib_query->link = link;
330 	ib_query->trans = trans;
331 	ib_query->result_res_id = 0;
332 	ib_query->result = NULL;
333 	ib_query->stmt = NULL;
334 	ib_query->in_array = NULL;
335 	ib_query->out_array = NULL;
336 	ib_query->dialect = dialect;
337 	ib_query->query = estrdup(query);
338 	ib_query->trans_res_id = trans_res_id;
339 	ib_query->out_sqlda = NULL;
340 	ib_query->in_sqlda = NULL;
341 
342 	if (isc_dsql_allocate_statement(IB_STATUS, &link->handle, &ib_query->stmt)) {
343 		_php_ibase_error(TSRMLS_C);
344 		goto _php_ibase_alloc_query_error;
345 	}
346 
347 	ib_query->out_sqlda = (XSQLDA *) emalloc(XSQLDA_LENGTH(1));
348 	ib_query->out_sqlda->sqln = 1;
349 	ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION;
350 
351 	if (isc_dsql_prepare(IB_STATUS, &ib_query->trans->handle, &ib_query->stmt,
352 			0, query, dialect, ib_query->out_sqlda)) {
353 		_php_ibase_error(TSRMLS_C);
354 		goto _php_ibase_alloc_query_error;
355 	}
356 
357 	/* find out what kind of statement was prepared */
358 	if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_type),
359 			info_type, sizeof(result), result)) {
360 		_php_ibase_error(TSRMLS_C);
361 		goto _php_ibase_alloc_query_error;
362 	}
363 	ib_query->statement_type = result[3];
364 
365 	/* not enough output variables ? */
366 	if (ib_query->out_sqlda->sqld > ib_query->out_sqlda->sqln) {
367 		ib_query->out_sqlda = erealloc(ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
368 		ib_query->out_sqlda->sqln = ib_query->out_sqlda->sqld;
369 		ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION;
370 		if (isc_dsql_describe(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->out_sqlda)) {
371 			_php_ibase_error(TSRMLS_C);
372 			goto _php_ibase_alloc_query_error;
373 		}
374 	}
375 
376 	/* maybe have input placeholders? */
377 	ib_query->in_sqlda = emalloc(XSQLDA_LENGTH(1));
378 	ib_query->in_sqlda->sqln = 1;
379 	ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION;
380 	if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) {
381 		_php_ibase_error(TSRMLS_C);
382 		goto _php_ibase_alloc_query_error;
383 	}
384 
385 	/* not enough input variables ? */
386 	if (ib_query->in_sqlda->sqln < ib_query->in_sqlda->sqld) {
387 		ib_query->in_sqlda = erealloc(ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
388 		ib_query->in_sqlda->sqln = ib_query->in_sqlda->sqld;
389 		ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION;
390 
391 		if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt,
392 				SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) {
393 			_php_ibase_error(TSRMLS_C);
394 			goto _php_ibase_alloc_query_error;
395 		}
396 	}
397 
398 	/* no, haven't placeholders at all */
399 	if (ib_query->in_sqlda->sqld == 0) {
400 		efree(ib_query->in_sqlda);
401 		ib_query->in_sqlda = NULL;
402 	} else if (FAILURE == _php_ibase_alloc_array(&ib_query->in_array, ib_query->in_sqlda,
403 			link->handle, trans->handle, &ib_query->in_array_cnt TSRMLS_CC)) {
404 		goto _php_ibase_alloc_query_error;
405 	}
406 
407 	if (ib_query->out_sqlda->sqld == 0) {
408 		efree(ib_query->out_sqlda);
409 		ib_query->out_sqlda = NULL;
410 	} else 	if (FAILURE == _php_ibase_alloc_array(&ib_query->out_array, ib_query->out_sqlda,
411 			link->handle, trans->handle, &ib_query->out_array_cnt TSRMLS_CC)) {
412 		goto _php_ibase_alloc_query_error;
413 	}
414 
415 	return SUCCESS;
416 
417 _php_ibase_alloc_query_error:
418 
419 	if (ib_query->out_sqlda) {
420 		efree(ib_query->out_sqlda);
421 	}
422 	if (ib_query->in_sqlda) {
423 		efree(ib_query->in_sqlda);
424 	}
425 	if (ib_query->out_array) {
426 		efree(ib_query->out_array);
427 	}
428 	if (ib_query->query) {
429 		efree(ib_query->query);
430 	}
431 	return FAILURE;
432 }
433 /* }}} */
434 
_php_ibase_bind_array(zval * val,char * buf,unsigned long buf_size,ibase_array * array,int dim TSRMLS_DC)435 static int _php_ibase_bind_array(zval *val, char *buf, unsigned long buf_size, /* {{{ */
436 	ibase_array *array, int dim TSRMLS_DC)
437 {
438 	zval null_val, *pnull_val = &null_val;
439 	int u_bound = array->ar_desc.array_desc_bounds[dim].array_bound_upper,
440 		l_bound = array->ar_desc.array_desc_bounds[dim].array_bound_lower,
441 		dim_len = 1 + u_bound - l_bound;
442 
443 	ZVAL_NULL(pnull_val);
444 
445 	if (dim < array->ar_desc.array_desc_dimensions) {
446 		unsigned long slice_size = buf_size / dim_len;
447 		unsigned short i;
448 		zval **subval = &val;
449 
450 		if (Z_TYPE_P(val) == IS_ARRAY) {
451 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
452 		}
453 
454 		for (i = 0; i < dim_len; ++i) {
455 
456 			if (Z_TYPE_P(val) == IS_ARRAY &&
457 				zend_hash_get_current_data(Z_ARRVAL_P(val), (void *) &subval) == FAILURE)
458 			{
459 				subval = &pnull_val;
460 			}
461 
462 			if (_php_ibase_bind_array(*subval, buf, slice_size, array, dim+1 TSRMLS_CC) == FAILURE)
463 			{
464 				return FAILURE;
465 			}
466 			buf += slice_size;
467 
468 			if (Z_TYPE_P(val) == IS_ARRAY) {
469 				zend_hash_move_forward(Z_ARRVAL_P(val));
470 			}
471 		}
472 
473 		if (Z_TYPE_P(val) == IS_ARRAY) {
474 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
475 		}
476 
477 	} else {
478 		/* expect a single value */
479 		if (Z_TYPE_P(val) == IS_NULL) {
480 			memset(buf, 0, buf_size);
481 		} else if (array->ar_desc.array_desc_scale < 0) {
482 
483 			/* no coercion for array types */
484 			double l;
485 
486 			convert_to_double(val);
487 
488 			if (Z_DVAL_P(val) > 0) {
489 				l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) + .5;
490 			} else {
491 				l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) - .5;
492 			}
493 
494 			switch (array->el_type) {
495 				case SQL_SHORT:
496 					if (l > SHRT_MAX || l < SHRT_MIN) {
497 						_php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
498 						return FAILURE;
499 					}
500 					*(short*) buf = (short) l;
501 					break;
502 				case SQL_LONG:
503 					if (l > ISC_LONG_MAX || l < ISC_LONG_MIN) {
504 						_php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
505 						return FAILURE;
506 					}
507 					*(ISC_LONG*) buf = (ISC_LONG) l;
508 					break;
509 				case SQL_INT64:
510 					{
511 						long double l;
512 
513 						convert_to_string(val);
514 
515 						if (!sscanf(Z_STRVAL_P(val), "%Lf", &l)) {
516 							_php_ibase_module_error("Cannot convert '%s' to long double"
517 								TSRMLS_CC, Z_STRVAL_P(val));
518 							return FAILURE;
519 						}
520 
521 						if (l > 0) {
522 							*(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10,
523 								-array->ar_desc.array_desc_scale) + .5);
524 						} else {
525 							*(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10,
526 								-array->ar_desc.array_desc_scale) - .5);
527 						}
528 					}
529 					break;
530 			}
531 		} else {
532 			struct tm t = { 0, 0, 0, 0, 0, 0 };
533 
534 			switch (array->el_type) {
535 				unsigned short n;
536 				ISC_INT64 l;
537 
538 				case SQL_SHORT:
539 					convert_to_long(val);
540 					if (Z_LVAL_P(val) > SHRT_MAX || Z_LVAL_P(val) < SHRT_MIN) {
541 						_php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
542 						return FAILURE;
543 					}
544 					*(short *) buf = (short) Z_LVAL_P(val);
545 					break;
546 				case SQL_LONG:
547 					convert_to_long(val);
548 #if (SIZEOF_LONG > 4)
549 					if (Z_LVAL_P(val) > ISC_LONG_MAX || Z_LVAL_P(val) < ISC_LONG_MIN) {
550 						_php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
551 						return FAILURE;
552 					}
553 #endif
554 					*(ISC_LONG *) buf = (ISC_LONG) Z_LVAL_P(val);
555 					break;
556 				case SQL_INT64:
557 #if (SIZEOF_LONG >= 8)
558 					convert_to_long(val);
559 					*(long *) buf = Z_LVAL_P(val);
560 #else
561 					convert_to_string(val);
562 					if (!sscanf(Z_STRVAL_P(val), "%" LL_MASK "d", &l)) {
563 						_php_ibase_module_error("Cannot convert '%s' to long integer"
564 							TSRMLS_CC, Z_STRVAL_P(val));
565 						return FAILURE;
566 					} else {
567 						*(ISC_INT64 *) buf = l;
568 					}
569 #endif
570 					break;
571 				case SQL_FLOAT:
572 					convert_to_double(val);
573 					*(float*) buf = (float) Z_DVAL_P(val);
574 					break;
575 				case SQL_DOUBLE:
576 					convert_to_double(val);
577 					*(double*) buf = Z_DVAL_P(val);
578 					break;
579 				case SQL_TIMESTAMP:
580 					convert_to_string(val);
581 #ifdef HAVE_STRPTIME
582 					strptime(Z_STRVAL_P(val), INI_STR("ibase.timestampformat"), &t);
583 #else
584 					n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d",
585 						&t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec);
586 
587 					if (n != 3 && n != 6) {
588 						_php_ibase_module_error("Invalid date/time format (expected 3 or 6 fields, got %d."
589 							" Use format 'm/d/Y H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
590 						return FAILURE;
591 					}
592 					t.tm_year -= 1900;
593 					t.tm_mon--;
594 #endif
595 					isc_encode_timestamp(&t, (ISC_TIMESTAMP * ) buf);
596 					break;
597 				case SQL_TYPE_DATE:
598 					convert_to_string(val);
599 #ifdef HAVE_STRPTIME
600 					strptime(Z_STRVAL_P(val), INI_STR("ibase.dateformat"), &t);
601 #else
602 					n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d", &t.tm_mon, &t.tm_mday, &t.tm_year);
603 
604 					if (n != 3) {
605 						_php_ibase_module_error("Invalid date format (expected 3 fields, got %d. "
606 							"Use format 'm/d/Y' You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
607 						return FAILURE;
608 					}
609 					t.tm_year -= 1900;
610 					t.tm_mon--;
611 #endif
612 					isc_encode_sql_date(&t, (ISC_DATE *) buf);
613 					break;
614 				case SQL_TYPE_TIME:
615 					convert_to_string(val);
616 #ifdef HAVE_STRPTIME
617 					strptime(Z_STRVAL_P(val), INI_STR("ibase.timeformat"), &t);
618 #else
619 					n = sscanf(Z_STRVAL_P(val), "%d%*[:]%d%*[:]%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
620 
621 					if (n != 3) {
622 						_php_ibase_module_error("Invalid time format (expected 3 fields, got %d. "
623 							"Use format 'H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
624 						return FAILURE;
625 					}
626 #endif
627 					isc_encode_sql_time(&t, (ISC_TIME *) buf);
628 					break;
629 				default:
630 					convert_to_string(val);
631 					strlcpy(buf, Z_STRVAL_P(val), buf_size);
632 			}
633 		}
634 	}
635 	return SUCCESS;
636 }
637 /* }}} */
638 
_php_ibase_bind(XSQLDA * sqlda,zval *** b_vars,BIND_BUF * buf,ibase_query * ib_query TSRMLS_DC)639 static int _php_ibase_bind(XSQLDA *sqlda, zval ***b_vars, BIND_BUF *buf, /* {{{ */
640 	ibase_query *ib_query TSRMLS_DC)
641 {
642 	int i, array_cnt = 0, rv = SUCCESS;
643 
644 	for (i = 0; i < sqlda->sqld; ++i) { /* bound vars */
645 
646 		zval *b_var = *b_vars[i];
647 		XSQLVAR *var = &sqlda->sqlvar[i];
648 
649 		var->sqlind = &buf[i].sqlind;
650 
651 		/* check if a NULL should be inserted */
652 		switch (Z_TYPE_P(b_var)) {
653 			int force_null;
654 
655 			case IS_STRING:
656 
657 				force_null = 0;
658 
659 				/* for these types, an empty string can be handled like a NULL value */
660 				switch (var->sqltype & ~1) {
661 					case SQL_SHORT:
662 					case SQL_LONG:
663 					case SQL_INT64:
664 					case SQL_FLOAT:
665 					case SQL_DOUBLE:
666 					case SQL_TIMESTAMP:
667 					case SQL_TYPE_DATE:
668 					case SQL_TYPE_TIME:
669 						force_null = (Z_STRLEN_P(b_var) == 0);
670 				}
671 
672 				if (! force_null) break;
673 
674 			case IS_NULL:
675 					buf[i].sqlind = -1;
676 
677 				if (var->sqltype & SQL_ARRAY) ++array_cnt;
678 
679 				continue;
680 		}
681 
682 		/* if we make it to this point, we must provide a value for the parameter */
683 
684 		buf[i].sqlind = 0;
685 
686 		var->sqldata = (void*)&buf[i].val;
687 
688 		switch (var->sqltype & ~1) {
689 			struct tm t;
690 
691 			case SQL_TIMESTAMP:
692 			case SQL_TYPE_DATE:
693 			case SQL_TYPE_TIME:
694 				if (Z_TYPE_P(b_var) == IS_LONG) {
695 					struct tm *res;
696 					res = php_gmtime_r(&Z_LVAL_P(b_var), &t);
697 					if (!res) {
698 						return FAILURE;
699 					}
700 				} else {
701 #ifdef HAVE_STRPTIME
702 					char *format = INI_STR("ibase.timestampformat");
703 
704 					convert_to_string(b_var);
705 
706 					switch (var->sqltype & ~1) {
707 						case SQL_TYPE_DATE:
708 							format = INI_STR("ibase.dateformat");
709 							break;
710 						case SQL_TYPE_TIME:
711 							format = INI_STR("ibase.timeformat");
712 					}
713 					if (!strptime(Z_STRVAL_P(b_var), format, &t)) {
714 						/* strptime() cannot handle it, so let IB have a try */
715 						break;
716 					}
717 #else /* ifndef HAVE_STRPTIME */
718 					break; /* let IB parse it as a string */
719 #endif
720 				}
721 
722 				switch (var->sqltype & ~1) {
723 					default: /* == case SQL_TIMESTAMP */
724 						isc_encode_timestamp(&t, &buf[i].val.tsval);
725 						break;
726 					case SQL_TYPE_DATE:
727 						isc_encode_sql_date(&t, &buf[i].val.dtval);
728 						break;
729 					case SQL_TYPE_TIME:
730 						isc_encode_sql_time(&t, &buf[i].val.tmval);
731 						break;
732 				}
733 				continue;
734 
735 			case SQL_BLOB:
736 
737 				convert_to_string(b_var);
738 
739 				if (Z_STRLEN_P(b_var) != BLOB_ID_LEN ||
740 					!_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) {
741 
742 					ibase_blob ib_blob = { NULL, BLOB_INPUT };
743 
744 					if (isc_create_blob(IB_STATUS, &ib_query->link->handle,
745 							&ib_query->trans->handle, &ib_blob.bl_handle, &ib_blob.bl_qd)) {
746 						_php_ibase_error(TSRMLS_C);
747 						return FAILURE;
748 					}
749 
750 					if (_php_ibase_blob_add(&b_var, &ib_blob TSRMLS_CC) != SUCCESS) {
751 						return FAILURE;
752 					}
753 
754 					if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
755 						_php_ibase_error(TSRMLS_C);
756 						return FAILURE;
757 					}
758 					buf[i].val.qval = ib_blob.bl_qd;
759 				}
760 				continue;
761 
762 			case SQL_ARRAY:
763 
764 				if (Z_TYPE_P(b_var) != IS_ARRAY) {
765 					convert_to_string(b_var);
766 
767 					if (Z_STRLEN_P(b_var) != BLOB_ID_LEN ||
768 						!_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) {
769 
770 						_php_ibase_module_error("Parameter %d: invalid array ID" TSRMLS_CC,i+1);
771 						rv = FAILURE;
772 					}
773 				} else {
774 					/* convert the array data into something IB can understand */
775 					ibase_array *ar = &ib_query->in_array[array_cnt];
776 					void *array_data = emalloc(ar->ar_size);
777 					ISC_QUAD array_id = { 0, 0 };
778 
779 					if (FAILURE == _php_ibase_bind_array(b_var, array_data, ar->ar_size,
780 							ar, 0 TSRMLS_CC)) {
781 						_php_ibase_module_error("Parameter %d: failed to bind array argument"
782 							TSRMLS_CC,i+1);
783 						efree(array_data);
784 						rv = FAILURE;
785 						continue;
786 					}
787 
788 					if (isc_array_put_slice(IB_STATUS, &ib_query->link->handle, &ib_query->trans->handle,
789 							&array_id, &ar->ar_desc, array_data, &ar->ar_size)) {
790 						_php_ibase_error(TSRMLS_C);
791 						efree(array_data);
792 						return FAILURE;
793 					}
794 					buf[i].val.qval = array_id;
795 					efree(array_data);
796 				}
797 				++array_cnt;
798 				continue;
799 			} /* switch */
800 
801 			/* we end up here if none of the switch cases handled the field */
802 			convert_to_string(b_var);
803 			var->sqldata = Z_STRVAL_P(b_var);
804 			var->sqllen	 = Z_STRLEN_P(b_var);
805 			var->sqltype = SQL_TEXT;
806 	} /* for */
807 	return rv;
808 }
809 /* }}} */
810 
_php_ibase_alloc_xsqlda(XSQLDA * sqlda)811 static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */
812 {
813 	int i;
814 
815 	for (i = 0; i < sqlda->sqld; i++) {
816 		XSQLVAR *var = &sqlda->sqlvar[i];
817 
818 		switch (var->sqltype & ~1) {
819 			case SQL_TEXT:
820 				var->sqldata = safe_emalloc(sizeof(char), var->sqllen, 0);
821 				break;
822 			case SQL_VARYING:
823 				var->sqldata = safe_emalloc(sizeof(char), var->sqllen + sizeof(short), 0);
824 				break;
825 			case SQL_SHORT:
826 				var->sqldata = emalloc(sizeof(short));
827 				break;
828 			case SQL_LONG:
829 				var->sqldata = emalloc(sizeof(ISC_LONG));
830 				break;
831 			case SQL_FLOAT:
832 				var->sqldata = emalloc(sizeof(float));
833 					break;
834 			case SQL_DOUBLE:
835 				var->sqldata = emalloc(sizeof(double));
836 				break;
837 			case SQL_INT64:
838 				var->sqldata = emalloc(sizeof(ISC_INT64));
839 				break;
840 			case SQL_TIMESTAMP:
841 				var->sqldata = emalloc(sizeof(ISC_TIMESTAMP));
842 				break;
843 			case SQL_TYPE_DATE:
844 				var->sqldata = emalloc(sizeof(ISC_DATE));
845 				break;
846 			case SQL_TYPE_TIME:
847 				var->sqldata = emalloc(sizeof(ISC_TIME));
848 				break;
849 			case SQL_BLOB:
850 			case SQL_ARRAY:
851 				var->sqldata = emalloc(sizeof(ISC_QUAD));
852 				break;
853 		} /* switch */
854 
855 		if (var->sqltype & 1) { /* sql NULL flag */
856 			var->sqlind = emalloc(sizeof(short));
857 		} else {
858 			var->sqlind = NULL;
859 		}
860 	} /* for */
861 }
862 /* }}} */
863 
_php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS,ibase_result ** ib_resultp,ibase_query * ib_query,zval *** args)864 static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resultp, /* {{{ */
865 	ibase_query *ib_query, zval ***args)
866 {
867 	XSQLDA *in_sqlda = NULL, *out_sqlda = NULL;
868 	BIND_BUF *bind_buf = NULL;
869 	int i, rv = FAILURE;
870 	static char info_count[] = { isc_info_sql_records };
871 	char result[64];
872 	ISC_STATUS isc_result;
873 	int argc = ib_query->in_sqlda ? ib_query->in_sqlda->sqld : 0;
874 
875 	RESET_ERRMSG;
876 
877 	for (i = 0; i < argc; ++i) {
878 		SEPARATE_ZVAL(args[i]);
879 	}
880 
881 	switch (ib_query->statement_type) {
882 		isc_tr_handle tr;
883 		ibase_tr_list **l;
884 		ibase_trans *trans;
885 
886 		case isc_info_sql_stmt_start_trans:
887 
888 			/* a SET TRANSACTION statement should be executed with a NULL trans handle */
889 			tr = NULL;
890 
891 			if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, &tr, 0,
892 					ib_query->query, ib_query->dialect, NULL)) {
893 				_php_ibase_error(TSRMLS_C);
894 				goto _php_ibase_exec_error;
895 			}
896 
897 			trans = (ibase_trans *) emalloc(sizeof(ibase_trans));
898 			trans->handle = tr;
899 			trans->link_cnt = 1;
900 			trans->affected_rows = 0;
901 			trans->db_link[0] = ib_query->link;
902 
903 			if (ib_query->link->tr_list == NULL) {
904 				ib_query->link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
905 				ib_query->link->tr_list->trans = NULL;
906 				ib_query->link->tr_list->next = NULL;
907 			}
908 
909 			/* link the transaction into the connection-transaction list */
910 			for (l = &ib_query->link->tr_list; *l != NULL; l = &(*l)->next);
911 			*l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
912 			(*l)->trans = trans;
913 			(*l)->next = NULL;
914 
915 			ZEND_REGISTER_RESOURCE(return_value, trans, le_trans);
916 
917 			return SUCCESS;
918 
919 		case isc_info_sql_stmt_commit:
920 		case isc_info_sql_stmt_rollback:
921 
922 			if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle,
923 					&ib_query->trans->handle, 0, ib_query->query, ib_query->dialect, NULL)) {
924 				_php_ibase_error(TSRMLS_C);
925 				goto _php_ibase_exec_error;
926 			}
927 
928 			if (ib_query->trans->handle == NULL && ib_query->trans_res_id != 0) {
929 				/* transaction was released by the query and was a registered resource,
930 				   so we have to release it */
931 				zend_list_delete(ib_query->trans_res_id);
932 			}
933 
934 			RETVAL_TRUE;
935 
936 			return SUCCESS;
937 
938 		default:
939 			RETVAL_FALSE;
940 	}
941 
942 	/* allocate sqlda and output buffers */
943 	if (ib_query->out_sqlda) { /* output variables in select, select for update */
944 		ibase_result *res;
945 
946 		IBDEBUG("Query wants XSQLDA for output");
947 		res = emalloc(sizeof(ibase_result)+sizeof(ibase_array)*max(0,ib_query->out_array_cnt-1));
948 		res->link = ib_query->link;
949 		res->trans = ib_query->trans;
950 		res->stmt = ib_query->stmt;
951 		/* ib_result and ib_query point at each other to handle release of statement handle properly */
952 		res->query = ib_query;
953 		ib_query->result = res;
954 		res->statement_type = ib_query->statement_type;
955 		res->has_more_rows = 1;
956 
957 		out_sqlda = res->out_sqlda = emalloc(XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
958 		memcpy(out_sqlda, ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
959 		_php_ibase_alloc_xsqlda(out_sqlda);
960 
961 		if (ib_query->out_array) {
962 			memcpy(&res->out_array, ib_query->out_array, sizeof(ibase_array)*ib_query->out_array_cnt);
963 		}
964 		*ib_resultp = res;
965 	}
966 
967 	if (ib_query->in_sqlda) { /* has placeholders */
968 		IBDEBUG("Query wants XSQLDA for input");
969 		in_sqlda = emalloc(XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
970 		memcpy(in_sqlda, ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
971 		bind_buf = safe_emalloc(sizeof(BIND_BUF), ib_query->in_sqlda->sqld, 0);
972 		if (_php_ibase_bind(in_sqlda, args, bind_buf, ib_query TSRMLS_CC) == FAILURE) {
973 			IBDEBUG("Could not bind input XSQLDA");
974 			goto _php_ibase_exec_error;
975 		}
976 	}
977 
978 	if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) {
979 		isc_result = isc_dsql_execute2(IB_STATUS, &ib_query->trans->handle,
980 			&ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda, out_sqlda);
981 	} else {
982 		isc_result = isc_dsql_execute(IB_STATUS, &ib_query->trans->handle,
983 			&ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda);
984 	}
985 	if (isc_result) {
986 		IBDEBUG("Could not execute query");
987 		_php_ibase_error(TSRMLS_C);
988 		goto _php_ibase_exec_error;
989 	}
990 	ib_query->trans->affected_rows = 0;
991 
992 	switch (ib_query->statement_type) {
993 
994 		unsigned long affected_rows;
995 
996 		case isc_info_sql_stmt_insert:
997 		case isc_info_sql_stmt_update:
998 		case isc_info_sql_stmt_delete:
999 		case isc_info_sql_stmt_exec_procedure:
1000 
1001 			if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_count),
1002 					info_count, sizeof(result), result)) {
1003 				_php_ibase_error(TSRMLS_C);
1004 				goto _php_ibase_exec_error;
1005 			}
1006 
1007 			affected_rows = 0;
1008 
1009 			if (result[0] == isc_info_sql_records) {
1010 				unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
1011 
1012 				while (result[i] != isc_info_end && i < result_size) {
1013 					short len = (short)isc_vax_integer(&result[i+1],2);
1014 					if (result[i] != isc_info_req_select_count) {
1015 						affected_rows += isc_vax_integer(&result[i+3],len);
1016 					}
1017 					i += len+3;
1018 				}
1019 			}
1020 
1021 			ib_query->trans->affected_rows = affected_rows;
1022 
1023 			if (!ib_query->out_sqlda) { /* no result set is being returned */
1024 				if (affected_rows) {
1025 					RETVAL_LONG(affected_rows);
1026 				} else {
1027 					RETVAL_TRUE;
1028 				}
1029 				break;
1030 			}
1031 		default:
1032 			RETVAL_TRUE;
1033 	}
1034 
1035 	rv = SUCCESS;
1036 
1037 _php_ibase_exec_error:
1038 
1039 	if (in_sqlda) {
1040 		efree(in_sqlda);
1041 	}
1042 	if (bind_buf)
1043 		efree(bind_buf);
1044 
1045 	if (rv == FAILURE) {
1046 		if (*ib_resultp) {
1047 			efree(*ib_resultp);
1048 			*ib_resultp = NULL;
1049 		}
1050 		if (out_sqlda) {
1051 			_php_ibase_free_xsqlda(out_sqlda);
1052 		}
1053 	}
1054 
1055 	return rv;
1056 }
1057 /* }}} */
1058 
1059 /* {{{ proto mixed ibase_query([resource link_identifier, [ resource link_identifier, ]] string query [, mixed bind_arg [, mixed bind_arg [, ...]]])
1060    Execute a query */
PHP_FUNCTION(ibase_query)1061 PHP_FUNCTION(ibase_query)
1062 {
1063 	zval *zlink, *ztrans, ***bind_args = NULL;
1064 	char *query;
1065 	int bind_i, query_len, bind_num;
1066 	long trans_res_id = 0;
1067 	ibase_db_link *ib_link = NULL;
1068 	ibase_trans *trans = NULL;
1069 	ibase_query ib_query = { NULL, NULL, 0, 0 };
1070 	ibase_result *result = NULL;
1071 
1072 	RESET_ERRMSG;
1073 
1074 	RETVAL_FALSE;
1075 
1076 	switch (ZEND_NUM_ARGS()) {
1077 		long l;
1078 
1079 		default:
1080 		    if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "rrs",
1081 					&zlink, &ztrans, &query, &query_len)) {
1082 
1083 				ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, &zlink, -1, LE_LINK, le_link, le_plink);
1084 				ZEND_FETCH_RESOURCE(trans, ibase_trans*, &ztrans, -1, LE_TRANS,	le_trans);
1085 
1086 				trans_res_id = Z_LVAL_P(ztrans);
1087 				bind_i = 3;
1088 				break;
1089 		    }
1090 		case 2:
1091 			if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "rs",
1092 					&zlink, &query, &query_len)) {
1093 				_php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &zlink, &ib_link, &trans);
1094 
1095 				if (trans != NULL) {
1096 					trans_res_id = Z_LVAL_P(zlink);
1097 				}
1098 				bind_i = 2;
1099 				break;
1100 			}
1101 
1102 			/* the statement is 'CREATE DATABASE ...' if the link argument is IBASE_CREATE */
1103 			if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS()
1104 					TSRMLS_CC, "ls", &l, &query, &query_len) && l == PHP_IBASE_CREATE) {
1105 				isc_db_handle db = NULL;
1106 				isc_tr_handle trans = NULL;
1107 
1108 				if (PG(sql_safe_mode)) {
1109 					_php_ibase_module_error("CREATE DATABASE is not allowed in SQL safe mode"
1110 						TSRMLS_CC);
1111 
1112 				} else if (((l = INI_INT("ibase.max_links")) != -1) && (IBG(num_links) >= l)) {
1113 					_php_ibase_module_error("CREATE DATABASE is not allowed: maximum link count "
1114 						"(%ld) reached" TSRMLS_CC, l);
1115 
1116 				} else if (isc_dsql_execute_immediate(IB_STATUS, &db, &trans, (short)query_len,
1117 						query, SQL_DIALECT_CURRENT, NULL)) {
1118 					_php_ibase_error(TSRMLS_C);
1119 
1120 				} else if (!db) {
1121 					_php_ibase_module_error("Connection to created database could not be "
1122 						"established" TSRMLS_CC);
1123 
1124 				} else {
1125 
1126 					/* register the link as a resource; unfortunately, we cannot register
1127 					   it in the hash table, because we don't know the connection params */
1128 					ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link));
1129 					ib_link->handle = db;
1130 					ib_link->dialect = SQL_DIALECT_CURRENT;
1131 					ib_link->tr_list = NULL;
1132 					ib_link->event_head = NULL;
1133 
1134 					ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link);
1135 					zend_list_addref(Z_LVAL_P(return_value));
1136 					IBG(default_link) = Z_LVAL_P(return_value);
1137 					++IBG(num_links);
1138 				}
1139 				return;
1140 			}
1141 		case 1:
1142 		case 0:
1143 			if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() ? 1 : 0 TSRMLS_CC, "s", &query,
1144 					&query_len)) {
1145 				ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK,
1146 			    	le_link, le_plink);
1147 
1148 				bind_i = 1;
1149 				break;
1150 			}
1151 			return;
1152 	}
1153 
1154 	/* open default transaction */
1155 	if (ib_link == NULL || FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC)
1156 			|| FAILURE == _php_ibase_alloc_query(&ib_query, ib_link, trans, query, ib_link->dialect,
1157 				trans_res_id TSRMLS_CC)) {
1158 		return;
1159 	}
1160 
1161 	do {
1162 		int bind_n = ZEND_NUM_ARGS() - bind_i,
1163 		    expected_n = ib_query.in_sqlda ? ib_query.in_sqlda->sqld : 0;
1164 
1165 		if (bind_n != expected_n) {
1166 			php_error_docref(NULL TSRMLS_CC, (bind_n < expected_n) ? E_WARNING : E_NOTICE,
1167 				"Statement expects %d arguments, %d given", expected_n, bind_n);
1168 			if (bind_n < expected_n) {
1169 				break;
1170 			}
1171 		} else if (bind_n > 0) {
1172 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &bind_args, &bind_num) == FAILURE) {
1173 				return;
1174 			}
1175 		}
1176 
1177 		if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, &ib_query,
1178 				&bind_args[bind_i])) {
1179 			break;
1180 		}
1181 
1182 		if (result != NULL) { /* statement returns a result */
1183 			result->type = QUERY_RESULT;
1184 
1185 			/* EXECUTE PROCEDURE returns only one row => statement can be released immediately */
1186 			if (ib_query.statement_type != isc_info_sql_stmt_exec_procedure) {
1187 				ib_query.stmt = NULL; /* keep stmt when free query */
1188 			}
1189 			ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1190 		}
1191 	} while (0);
1192 
1193 	_php_ibase_free_query(&ib_query TSRMLS_CC);
1194 
1195 	if (bind_args) {
1196 		efree(bind_args);
1197 	}
1198 }
1199 /* }}} */
1200 
1201 /* {{{ proto int ibase_affected_rows( [ resource link_identifier ] )
1202    Returns the number of rows affected by the previous INSERT, UPDATE or DELETE statement */
PHP_FUNCTION(ibase_affected_rows)1203 PHP_FUNCTION(ibase_affected_rows)
1204 {
1205 	ibase_trans *trans = NULL;
1206 	ibase_db_link *ib_link;
1207 	zval *arg = NULL;
1208 
1209 	RESET_ERRMSG;
1210 
1211 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg) == FAILURE) {
1212 		return;
1213 	}
1214 
1215 	if (!arg) {
1216 		ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
1217 		if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
1218 			RETURN_FALSE;
1219 		}
1220 		trans = ib_link->tr_list->trans;
1221 	} else {
1222 		/* one id was passed, could be db or trans id */
1223 		_php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &arg, &ib_link, &trans);
1224 		if (trans == NULL) {
1225 			ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &arg, -1, LE_LINK, le_link, le_plink);
1226 
1227 			if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
1228 				RETURN_FALSE;
1229 			}
1230 			trans = ib_link->tr_list->trans;
1231 		}
1232 	}
1233 	RETURN_LONG(trans->affected_rows);
1234 }
1235 /* }}} */
1236 
1237 /* {{{ proto int ibase_num_rows( resource result_identifier )
1238    Return the number of rows that are available in a result */
1239 #if abies_0
PHP_FUNCTION(ibase_num_rows)1240 PHP_FUNCTION(ibase_num_rows)
1241 {
1242 	/**
1243 	 * As this function relies on the InterBase API function isc_dsql_sql_info()
1244 	 * which has a couple of limitations (which I hope will be fixed in future
1245 	 * releases of Firebird), this function is fairly useless. I'm leaving it
1246 	 * in place for people who can live with the limitations, which I only
1247 	 * found out about after I had implemented it anyway.
1248 	 *
1249 	 * Currently, there's no way to determine how many rows can be fetched from
1250 	 * a cursor. The only number that _can_ be determined is the number of rows
1251 	 * that have already been pre-fetched by the client library.
1252 	 * This implies the following:
1253 	 * - num_rows() always returns zero before the first fetch;
1254 	 * - num_rows() for SELECT ... FOR UPDATE is broken -> never returns a
1255 	 *   higher number than the number of records fetched so far (no pre-fetch);
1256 	 * - the result of num_rows() for other statements is merely a lower bound
1257 	 *   on the number of records => calling ibase_num_rows() again after a couple
1258 	 *   of fetches will most likely return a new (higher) figure for large result
1259 	 *   sets.
1260 	 */
1261 
1262 	zval *result_arg;
1263 	ibase_result *ib_result;
1264 	static char info_count[] = {isc_info_sql_records};
1265 	char result[64];
1266 
1267 	RESET_ERRMSG;
1268 
1269 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result_arg) == FAILURE) {
1270 		return;
1271 	}
1272 
1273 	ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
1274 
1275 	if (isc_dsql_sql_info(IB_STATUS, &ib_result->stmt, sizeof(info_count), info_count, sizeof(result), result)) {
1276 		_php_ibase_error(TSRMLS_C);
1277 		RETURN_FALSE;
1278 	}
1279 
1280 	if (result[0] == isc_info_sql_records) {
1281 		unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
1282 
1283 		while (result[i] != isc_info_end && i < result_size) {
1284 			short len = (short)isc_vax_integer(&result[i+1],2);
1285 			if (result[i] == isc_info_req_select_count) {
1286 				RETURN_LONG(isc_vax_integer(&result[i+3],len));
1287 			}
1288 			i += len+3;
1289 		}
1290 	}
1291 }
1292 #endif
1293 /* }}} */
1294 
_php_ibase_var_zval(zval * val,void * data,int type,int len,int scale,int flag TSRMLS_DC)1295 static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ */
1296 	int scale, int flag TSRMLS_DC)
1297 {
1298 	static ISC_INT64 const scales[] = { 1, 10, 100, 1000,
1299 		10000,
1300 		100000,
1301 		1000000,
1302 		10000000,
1303 		100000000,
1304 		1000000000,
1305 		LL_LIT(10000000000),
1306 		LL_LIT(100000000000),
1307 		LL_LIT(1000000000000),
1308 		LL_LIT(10000000000000),
1309 		LL_LIT(100000000000000),
1310 		LL_LIT(1000000000000000),
1311 		LL_LIT(10000000000000000),
1312 		LL_LIT(100000000000000000),
1313 		LL_LIT(1000000000000000000)
1314 	};
1315 
1316 	switch (type & ~1) {
1317 		unsigned short l;
1318 		long n;
1319 		char string_data[255];
1320 		struct tm t;
1321 		char *format;
1322 
1323 		case SQL_VARYING:
1324 			len = ((IBVARY *) data)->vary_length;
1325 			data = ((IBVARY *) data)->vary_string;
1326 			/* no break */
1327 		case SQL_TEXT:
1328 			if (PG(magic_quotes_runtime)) {
1329 				Z_STRVAL_P(val) = php_addslashes(data, len, &Z_STRLEN_P(val), 0 TSRMLS_CC);
1330 				Z_TYPE_P(val) = IS_STRING;
1331 			} else {
1332 				ZVAL_STRINGL(val,(char *) data,len,1);
1333 			}
1334 			break;
1335 		case SQL_SHORT:
1336 			n = *(short *) data;
1337 			goto _sql_long;
1338 		case SQL_INT64:
1339 #if (SIZEOF_LONG >= 8)
1340 			n = *(long *) data;
1341 			goto _sql_long;
1342 #else
1343 			if (scale == 0) {
1344 				l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d", *(ISC_INT64 *) data);
1345 				ZVAL_STRINGL(val,string_data,l,1);
1346 			} else {
1347 				ISC_INT64 n = *(ISC_INT64 *) data, f = scales[-scale];
1348 
1349 				if (n >= 0) {
1350 					l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, n % f);
1351 				} else if (n <= -f) {
1352 					l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, -n % f);
1353 				 } else {
1354 					l = slprintf(string_data, sizeof(string_data), "-0.%0*" LL_MASK "d", -scale, -n % f);
1355 				}
1356 				ZVAL_STRINGL(val,string_data,l,1);
1357 			}
1358 			break;
1359 #endif
1360 		case SQL_LONG:
1361 			n = *(ISC_LONG *) data;
1362 		_sql_long:
1363 			if (scale == 0) {
1364 				ZVAL_LONG(val,n);
1365 			} else {
1366 				long f = (long) scales[-scale];
1367 
1368 				if (n >= 0) {
1369 					l = slprintf(string_data, sizeof(string_data), "%ld.%0*ld", n / f, -scale,  n % f);
1370 				} else if (n <= -f) {
1371 					l = slprintf(string_data, sizeof(string_data), "%ld.%0*ld", n / f, -scale,  -n % f);
1372 				} else {
1373 					l = slprintf(string_data, sizeof(string_data), "-0.%0*ld", -scale, -n % f);
1374 				}
1375 				ZVAL_STRINGL(val,string_data,l,1);
1376 			}
1377 			break;
1378 		case SQL_FLOAT:
1379 			ZVAL_DOUBLE(val, *(float *) data);
1380 			break;
1381 		case SQL_DOUBLE:
1382 			ZVAL_DOUBLE(val, *(double *) data);
1383 			break;
1384 		case SQL_DATE: /* == case SQL_TIMESTAMP: */
1385 			format = INI_STR("ibase.timestampformat");
1386 			isc_decode_timestamp((ISC_TIMESTAMP *) data, &t);
1387 			goto format_date_time;
1388 		case SQL_TYPE_DATE:
1389 			format = INI_STR("ibase.dateformat");
1390 			isc_decode_sql_date((ISC_DATE *) data, &t);
1391 			goto format_date_time;
1392 		case SQL_TYPE_TIME:
1393 			format = INI_STR("ibase.timeformat");
1394 			isc_decode_sql_time((ISC_TIME *) data, &t);
1395 
1396 format_date_time:
1397 			/*
1398 			  XXX - Might have to remove this later - seems that isc_decode_date()
1399 			   always sets tm_isdst to 0, sometimes incorrectly (InterBase 6 bug?)
1400 			*/
1401 			t.tm_isdst = -1;
1402 #if HAVE_TM_ZONE
1403 			t.tm_zone = tzname[0];
1404 #endif
1405 			if (flag & PHP_IBASE_UNIXTIME) {
1406 				ZVAL_LONG(val, mktime(&t));
1407 			} else {
1408 #if HAVE_STRFTIME
1409 				l = strftime(string_data, sizeof(string_data), format, &t);
1410 #else
1411 				switch (type & ~1) {
1412 					default:
1413 						l = slprintf(string_data, sizeof(string_data), "%02d/%02d/%4d %02d:%02d:%02d", t.tm_mon+1, t.tm_mday,
1414 							t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
1415 						break;
1416 					case SQL_TYPE_DATE:
1417 						l = slprintf(string_data, sizeof(string_data), "%02d/%02d/%4d", t.tm_mon + 1, t.tm_mday, t.tm_year+1900);
1418 						break;
1419 					case SQL_TYPE_TIME:
1420 						l = slprintf(string_data, sizeof(string_data), "%02d:%02d:%02d", t.tm_hour, t.tm_min, t.tm_sec);
1421 						break;
1422 				}
1423 #endif
1424 				ZVAL_STRINGL(val,string_data,l,1);
1425 				break;
1426 			}
1427 	} /* switch (type) */
1428 	return SUCCESS;
1429 }
1430 /* }}}	*/
1431 
_php_ibase_arr_zval(zval * ar_zval,char * data,unsigned long data_size,ibase_array * ib_array,int dim,int flag TSRMLS_DC)1432 static int _php_ibase_arr_zval(zval *ar_zval, char *data, unsigned long data_size, /* {{{ */
1433 	ibase_array *ib_array, int dim, int flag TSRMLS_DC)
1434 {
1435 	/**
1436 	 * Create multidimension array - recursion function
1437 	 */
1438 	int
1439 		u_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_upper,
1440 		l_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_lower,
1441 		dim_len = 1 + u_bound - l_bound;
1442 	unsigned short i;
1443 
1444 	if (dim < ib_array->ar_desc.array_desc_dimensions) { /* array again */
1445 		unsigned long slice_size = data_size / dim_len;
1446 
1447 		array_init(ar_zval);
1448 
1449 		for (i = 0; i < dim_len; ++i) {
1450 			zval *slice_zval;
1451 			ALLOC_INIT_ZVAL(slice_zval);
1452 
1453 			/* recursion here */
1454 			if (FAILURE == _php_ibase_arr_zval(slice_zval, data, slice_size, ib_array, dim + 1,
1455 					flag TSRMLS_CC)) {
1456 				return FAILURE;
1457 			}
1458 			data += slice_size;
1459 
1460 			add_index_zval(ar_zval,l_bound+i,slice_zval);
1461 		}
1462 	} else { /* data at last */
1463 
1464 		if (FAILURE == _php_ibase_var_zval(ar_zval, data, ib_array->el_type,
1465 				ib_array->ar_desc.array_desc_length, ib_array->ar_desc.array_desc_scale, flag TSRMLS_CC)) {
1466 			return FAILURE;
1467 		}
1468 
1469 		/* fix for peculiar handling of VARCHAR arrays;
1470 		   truncate the field to the cstring length */
1471 		if (ib_array->ar_desc.array_desc_dtype == blr_varying ||
1472 			ib_array->ar_desc.array_desc_dtype == blr_varying2) {
1473 
1474 			Z_STRLEN_P(ar_zval) = strlen(Z_STRVAL_P(ar_zval));
1475 		}
1476 	}
1477 	return SUCCESS;
1478 }
1479 /* }}} */
1480 
_php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS,int fetch_type)1481 static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type) /* {{{ */
1482 {
1483 	zval *result_arg;
1484 	long i, array_cnt = 0, flag = 0;
1485 	ibase_result *ib_result;
1486 
1487 	RESET_ERRMSG;
1488 
1489 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result_arg, &flag)) {
1490 		return;
1491 	}
1492 
1493 	ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
1494 
1495 	if (ib_result->out_sqlda == NULL || !ib_result->has_more_rows) {
1496 		RETURN_FALSE;
1497 	}
1498 
1499 	if (ib_result->statement_type != isc_info_sql_stmt_exec_procedure) {
1500 		if (isc_dsql_fetch(IB_STATUS, &ib_result->stmt, 1, ib_result->out_sqlda)) {
1501 			ib_result->has_more_rows = 0;
1502 			if (IB_STATUS[0] && IB_STATUS[1]) { /* error in fetch */
1503 				_php_ibase_error(TSRMLS_C);
1504 			}
1505 			RETURN_FALSE;
1506 		}
1507 	} else {
1508 		ib_result->has_more_rows = 0;
1509 	}
1510 
1511 	array_init(return_value);
1512 
1513 	for (i = 0; i < ib_result->out_sqlda->sqld; ++i) {
1514 		XSQLVAR *var = &ib_result->out_sqlda->sqlvar[i];
1515 		char buf[METADATALENGTH+4], *alias = var->aliasname;
1516 
1517 		if (! (fetch_type & FETCH_ROW)) {
1518 			int i = 0;
1519 			char const *base = "FIELD"; /* use 'FIELD' if name is empty */
1520 
1521 			/**
1522 			* Ensure no two columns have identical names:
1523 			* keep generating new names until we find one that is unique.
1524 			*/
1525 			switch (*alias) {
1526 				void *p;
1527 
1528 				default:
1529 					i = 1;
1530 					base = alias;
1531 
1532 					while (SUCCESS == zend_symtable_find(
1533 							Z_ARRVAL_P(return_value),alias,strlen(alias)+1,&p)) {
1534 
1535 				case '\0':
1536 						snprintf(alias = buf, sizeof(buf), "%s_%02d", base, i++);
1537 					}
1538 			}
1539 		}
1540 
1541 		if (((var->sqltype & 1) == 0) || *var->sqlind != -1) {
1542 			zval *result;
1543 			ALLOC_INIT_ZVAL(result);
1544 
1545 			switch (var->sqltype & ~1) {
1546 
1547 				default:
1548 					_php_ibase_var_zval(result, var->sqldata, var->sqltype, var->sqllen,
1549 						var->sqlscale, flag TSRMLS_CC);
1550 					break;
1551 				case SQL_BLOB:
1552 					if (flag & PHP_IBASE_FETCH_BLOBS) { /* fetch blob contents into hash */
1553 
1554 						ibase_blob blob_handle;
1555 						unsigned long max_len = 0;
1556 						static char bl_items[] = {isc_info_blob_total_length};
1557 						char bl_info[20];
1558 						unsigned short i;
1559 
1560 						blob_handle.bl_handle = NULL;
1561 						blob_handle.bl_qd = *(ISC_QUAD *) var->sqldata;
1562 
1563 						if (isc_open_blob(IB_STATUS, &ib_result->link->handle, &ib_result->trans->handle,
1564 								&blob_handle.bl_handle, &blob_handle.bl_qd)) {
1565 							_php_ibase_error(TSRMLS_C);
1566 							goto _php_ibase_fetch_error;
1567 						}
1568 
1569 						if (isc_blob_info(IB_STATUS, &blob_handle.bl_handle, sizeof(bl_items),
1570 								bl_items, sizeof(bl_info), bl_info)) {
1571 							_php_ibase_error(TSRMLS_C);
1572 							goto _php_ibase_fetch_error;
1573 						}
1574 
1575 						/* find total length of blob's data */
1576 						for (i = 0; i < sizeof(bl_info); ) {
1577 							unsigned short item_len;
1578 							char item = bl_info[i++];
1579 
1580 							if (item == isc_info_end || item == isc_info_truncated ||
1581 								item == isc_info_error || i >= sizeof(bl_info)) {
1582 
1583 								_php_ibase_module_error("Could not determine BLOB size (internal error)"
1584 									TSRMLS_CC);
1585 								goto _php_ibase_fetch_error;
1586 							}
1587 
1588 							item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2);
1589 
1590 							if (item == isc_info_blob_total_length) {
1591 								max_len = isc_vax_integer(&bl_info[i+2], item_len);
1592 								break;
1593 							}
1594 							i += item_len+2;
1595 						}
1596 
1597 						if (max_len == 0) {
1598 							ZVAL_STRING(result, "", 1);
1599 						} else if (SUCCESS != _php_ibase_blob_get(result, &blob_handle,
1600 								max_len TSRMLS_CC)) {
1601 							goto _php_ibase_fetch_error;
1602 						}
1603 
1604 						if (isc_close_blob(IB_STATUS, &blob_handle.bl_handle)) {
1605 							_php_ibase_error(TSRMLS_C);
1606 							goto _php_ibase_fetch_error;
1607 						}
1608 
1609 					} else { /* blob id only */
1610 						ISC_QUAD bl_qd = *(ISC_QUAD *) var->sqldata;
1611 						ZVAL_STRINGL(result,_php_ibase_quad_to_string(bl_qd), BLOB_ID_LEN, 0);
1612 					}
1613 					break;
1614 				case SQL_ARRAY:
1615 					if (flag & PHP_IBASE_FETCH_ARRAYS) { /* array can be *huge* so only fetch if asked */
1616 						ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
1617 						ibase_array *ib_array = &ib_result->out_array[array_cnt++];
1618 						void *ar_data = emalloc(ib_array->ar_size);
1619 
1620 						if (isc_array_get_slice(IB_STATUS, &ib_result->link->handle,
1621 								&ib_result->trans->handle, &ar_qd, &ib_array->ar_desc,
1622 								ar_data, &ib_array->ar_size)) {
1623 							_php_ibase_error(TSRMLS_C);
1624 							efree(ar_data);
1625 							goto _php_ibase_fetch_error;
1626 						}
1627 
1628 						if (FAILURE == _php_ibase_arr_zval(result, ar_data, ib_array->ar_size, ib_array,
1629 								0, flag TSRMLS_CC)) {
1630 							efree(ar_data);
1631 							goto _php_ibase_fetch_error;
1632 						}
1633 						efree(ar_data);
1634 
1635 					} else { /* blob id only */
1636 						ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
1637 						ZVAL_STRINGL(result,_php_ibase_quad_to_string(ar_qd), BLOB_ID_LEN, 0);
1638 					}
1639 					break;
1640 				_php_ibase_fetch_error:
1641 					zval_dtor(result);
1642 					FREE_ZVAL(result);
1643 					RETURN_FALSE;
1644 			} /* switch */
1645 
1646 			if (fetch_type & FETCH_ROW) {
1647 				add_index_zval(return_value, i, result);
1648 			} else {
1649 				add_assoc_zval(return_value, alias, result);
1650 			}
1651 		} else {
1652 			if (fetch_type & FETCH_ROW) {
1653 				add_index_null(return_value, i);
1654 			} else {
1655 				add_assoc_null(return_value, alias);
1656 			}
1657 		}
1658 	} /* for field */
1659 }
1660 /* }}} */
1661 
1662 /* {{{ proto array ibase_fetch_row(resource result [, int fetch_flags])
1663    Fetch a row  from the results of a query */
PHP_FUNCTION(ibase_fetch_row)1664 PHP_FUNCTION(ibase_fetch_row)
1665 {
1666 	_php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ROW);
1667 }
1668 /* }}} */
1669 
1670 /* {{{ proto array ibase_fetch_assoc(resource result [, int fetch_flags])
1671    Fetch a row  from the results of a query */
PHP_FUNCTION(ibase_fetch_assoc)1672 PHP_FUNCTION(ibase_fetch_assoc)
1673 {
1674 	_php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY);
1675 }
1676 /* }}} */
1677 
1678 /* {{{ proto object ibase_fetch_object(resource result [, int fetch_flags])
1679    Fetch a object from the results of a query */
PHP_FUNCTION(ibase_fetch_object)1680 PHP_FUNCTION(ibase_fetch_object)
1681 {
1682 	_php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY);
1683 
1684 	if (Z_TYPE_P(return_value) == IS_ARRAY) {
1685 		object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1686 	}
1687 }
1688 /* }}} */
1689 
1690 
1691 /* {{{ proto bool ibase_name_result(resource result, string name)
1692    Assign a name to a result for use with ... WHERE CURRENT OF <name> statements */
PHP_FUNCTION(ibase_name_result)1693 PHP_FUNCTION(ibase_name_result)
1694 {
1695 	zval *result_arg;
1696 	char *name_arg;
1697 	int name_arg_len;
1698 	ibase_result *ib_result;
1699 
1700 	RESET_ERRMSG;
1701 
1702 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &result_arg, &name_arg, &name_arg_len) == FAILURE) {
1703 		return;
1704 	}
1705 
1706 	ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
1707 
1708 	if (isc_dsql_set_cursor_name(IB_STATUS, &ib_result->stmt, name_arg, 0)) {
1709 		_php_ibase_error(TSRMLS_C);
1710 		RETURN_FALSE;
1711 	}
1712 	RETURN_TRUE;
1713 }
1714 /* }}} */
1715 
1716 
1717 /* {{{ proto bool ibase_free_result(resource result)
1718    Free the memory used by a result */
PHP_FUNCTION(ibase_free_result)1719 PHP_FUNCTION(ibase_free_result)
1720 {
1721 	zval *result_arg;
1722 	ibase_result *ib_result;
1723 
1724 	RESET_ERRMSG;
1725 
1726 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result_arg) == FAILURE) {
1727 		return;
1728 	}
1729 
1730 	ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
1731 	zend_list_delete(Z_RESVAL_P(result_arg));
1732 	RETURN_TRUE;
1733 }
1734 /* }}} */
1735 
1736 /* {{{ proto resource ibase_prepare(resource link_identifier[, string query [, resource trans_identifier ]])
1737    Prepare a query for later execution */
PHP_FUNCTION(ibase_prepare)1738 PHP_FUNCTION(ibase_prepare)
1739 {
1740 	zval *link_arg, *trans_arg;
1741 	ibase_db_link *ib_link;
1742 	ibase_trans *trans = NULL;
1743 	int query_len, trans_res_id = 0;
1744 	ibase_query *ib_query;
1745 	char *query;
1746 
1747 	RESET_ERRMSG;
1748 
1749 	if (ZEND_NUM_ARGS() == 1) {
1750 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
1751 			return;
1752 		}
1753 		ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
1754 	} else if (ZEND_NUM_ARGS() == 2) {
1755 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &link_arg, &query, &query_len) == FAILURE) {
1756 			return;
1757 		}
1758 		_php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &link_arg, &ib_link, &trans);
1759 
1760 		if (trans != NULL) {
1761 			trans_res_id = Z_RESVAL_P(link_arg);
1762 		}
1763 	} else {
1764 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrs", &link_arg, &trans_arg, &query, &query_len) == FAILURE) {
1765 			return;
1766 		}
1767 		ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, -1, LE_LINK, le_link, le_plink);
1768 		ZEND_FETCH_RESOURCE(trans, ibase_trans *, &trans_arg, -1, LE_TRANS, le_trans);
1769 		trans_res_id = Z_RESVAL_P(trans_arg);
1770 	}
1771 
1772 	if (FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC)) {
1773 		RETURN_FALSE;
1774 	}
1775 
1776 	ib_query = (ibase_query *) emalloc(sizeof(ibase_query));
1777 
1778 	if (FAILURE == _php_ibase_alloc_query(ib_query, ib_link, trans, query, ib_link->dialect, trans_res_id TSRMLS_CC)) {
1779 		efree(ib_query);
1780 		RETURN_FALSE;
1781 	}
1782 	ZEND_REGISTER_RESOURCE(return_value, ib_query, le_query);
1783 }
1784 /* }}} */
1785 
1786 /* {{{ proto mixed ibase_execute(resource query [, mixed bind_arg [, mixed bind_arg [, ...]]])
1787    Execute a previously prepared query */
PHP_FUNCTION(ibase_execute)1788 PHP_FUNCTION(ibase_execute)
1789 {
1790 	zval *query, ***args = NULL;
1791 	ibase_query *ib_query;
1792 	ibase_result *result = NULL;
1793 	ALLOCA_FLAG(use_heap)
1794 
1795 	RESET_ERRMSG;
1796 
1797 	RETVAL_FALSE;
1798 
1799 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() ? 1 : 0 TSRMLS_CC, "r", &query)) {
1800 		return;
1801 	}
1802 
1803 	ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &query, -1, LE_QUERY, le_query);
1804 
1805 	do {
1806 		int bind_n = ZEND_NUM_ARGS() - 1,
1807 			expected_n = ib_query->in_sqlda ? ib_query->in_sqlda->sqld : 0;
1808 
1809 		if (bind_n != expected_n) {
1810 			php_error_docref(NULL TSRMLS_CC, (bind_n < expected_n) ? E_WARNING : E_NOTICE,
1811 				"Statement expects %d arguments, %d given", expected_n, bind_n);
1812 
1813 			if (bind_n < expected_n) {
1814 				break;
1815 			}
1816 		}
1817 
1818 		/* have variables to bind */
1819 		args = (zval ***) do_alloca((expected_n + 1) * sizeof(zval **), use_heap);
1820 
1821 		if (FAILURE == zend_get_parameters_array_ex((expected_n + 1), args)) {
1822 			break;
1823 		}
1824 
1825 		/* Have we used this cursor before and it's still open (exec proc has no cursor) ? */
1826 		if (ib_query->result_res_id != 0
1827 				&& ib_query->statement_type != isc_info_sql_stmt_exec_procedure) {
1828 			IBDEBUG("Implicitly closing a cursor");
1829 
1830 			if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_close)) {
1831 				_php_ibase_error(TSRMLS_C);
1832 				break;
1833 			}
1834 			/* invalidate previous results returned by this query (not necessary for exec proc) */
1835 			zend_list_delete(ib_query->result_res_id);
1836 		}
1837 
1838 		if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, ib_query,
1839 				&args[1])) {
1840 		    break;
1841 		}
1842 
1843 		/* free the query if trans handle was released */
1844 		if (ib_query->trans->handle == NULL) {
1845 			zend_list_delete(Z_LVAL_P(query));
1846 		}
1847 
1848 		if (result != NULL) {
1849 			result->type = EXECUTE_RESULT;
1850 			if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) {
1851 				result->stmt = NULL;
1852 			}
1853 			ib_query->result_res_id = zend_list_insert(result, le_result);
1854 			RETVAL_RESOURCE(ib_query->result_res_id);
1855 		}
1856 	} while (0);
1857 
1858 	if (args) {
1859 		free_alloca(args, use_heap);
1860 	}
1861 }
1862 /* }}} */
1863 
1864 /* {{{ proto bool ibase_free_query(resource query)
1865    Free memory used by a query */
PHP_FUNCTION(ibase_free_query)1866 PHP_FUNCTION(ibase_free_query)
1867 {
1868 	zval *query_arg;
1869 	ibase_query *ib_query;
1870 
1871 	RESET_ERRMSG;
1872 
1873 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &query_arg) == FAILURE) {
1874 		return;
1875 	}
1876 
1877 	ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &query_arg, -1, LE_QUERY, le_query);
1878 	zend_list_delete(Z_RESVAL_P(query_arg));
1879 	RETURN_TRUE;
1880 }
1881 /* }}} */
1882 
1883 /* {{{ proto int ibase_num_fields(resource query_result)
1884    Get the number of fields in result */
PHP_FUNCTION(ibase_num_fields)1885 PHP_FUNCTION(ibase_num_fields)
1886 {
1887 	zval *result;
1888 	int type;
1889 	XSQLDA *sqlda;
1890 
1891 	RESET_ERRMSG;
1892 
1893 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
1894 		return;
1895 	}
1896 
1897 	zend_list_find(Z_RESVAL_P(result), &type);
1898 
1899 	if (type == le_query) {
1900 		ibase_query *ib_query;
1901 
1902 		ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result, -1, LE_QUERY, le_query);
1903 		sqlda = ib_query->out_sqlda;
1904 	} else {
1905 		ibase_result *ib_result;
1906 
1907 		ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result, -1, LE_RESULT, le_result);
1908 		sqlda = ib_result->out_sqlda;
1909 	}
1910 
1911 	if (sqlda == NULL) {
1912 		RETURN_LONG(0);
1913 	} else {
1914 		RETURN_LONG(sqlda->sqld);
1915 	}
1916 }
1917 /* }}} */
1918 
_php_ibase_field_info(zval * return_value,XSQLVAR * var)1919 static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */
1920 {
1921 	unsigned short len;
1922 	char buf[16], *s = buf;
1923 
1924 	array_init(return_value);
1925 
1926 	add_index_stringl(return_value, 0, var->sqlname, var->sqlname_length, 1);
1927 	add_assoc_stringl(return_value, "name", var->sqlname, var->sqlname_length, 1);
1928 
1929 	add_index_stringl(return_value, 1, var->aliasname, var->aliasname_length, 1);
1930 	add_assoc_stringl(return_value, "alias", var->aliasname, var->aliasname_length, 1);
1931 
1932 	add_index_stringl(return_value, 2, var->relname, var->relname_length, 1);
1933 	add_assoc_stringl(return_value, "relation", var->relname, var->relname_length, 1);
1934 
1935 	len = slprintf(buf, 16, "%d", var->sqllen);
1936 	add_index_stringl(return_value, 3, buf, len, 1);
1937 	add_assoc_stringl(return_value, "length", buf, len, 1);
1938 
1939 	if (var->sqlscale < 0) {
1940 		unsigned short precision = 0;
1941 
1942 		switch (var->sqltype & ~1) {
1943 
1944 			case SQL_SHORT:
1945 				precision = 4;
1946 				break;
1947 			case SQL_LONG:
1948 				precision = 9;
1949 				break;
1950 			case SQL_INT64:
1951 				precision = 18;
1952 				break;
1953 		}
1954 		len = slprintf(buf, 16, "NUMERIC(%d,%d)", precision, -var->sqlscale);
1955 		add_index_stringl(return_value, 4, s, len, 1);
1956 		add_assoc_stringl(return_value, "type", s, len, 1);
1957 	} else {
1958 		switch (var->sqltype & ~1) {
1959 			case SQL_TEXT:
1960 				s = "CHAR";
1961 				break;
1962 			case SQL_VARYING:
1963 				s = "VARCHAR";
1964 				break;
1965 			case SQL_SHORT:
1966 				s = "SMALLINT";
1967 				break;
1968 			case SQL_LONG:
1969 				s = "INTEGER";
1970 				break;
1971 			case SQL_FLOAT:
1972 				s = "FLOAT"; break;
1973 			case SQL_DOUBLE:
1974 			case SQL_D_FLOAT:
1975 				s = "DOUBLE PRECISION"; break;
1976 			case SQL_INT64:
1977 				s = "BIGINT";
1978 				break;
1979 			case SQL_TIMESTAMP:
1980 				s = "TIMESTAMP";
1981 				break;
1982 			case SQL_TYPE_DATE:
1983 				s = "DATE";
1984 				break;
1985 			case SQL_TYPE_TIME:
1986 				s = "TIME";
1987 				break;
1988 			case SQL_BLOB:
1989 				s = "BLOB";
1990 				break;
1991 			case SQL_ARRAY:
1992 				s = "ARRAY";
1993 				break;
1994 				/* FIXME: provide more detailed information about the field type, field size
1995 				 * and array dimensions */
1996 			case SQL_QUAD:
1997 				s = "QUAD";
1998 				break;
1999 		}
2000 		add_index_string(return_value, 4, s, 1);
2001 		add_assoc_string(return_value, "type", s, 1);
2002 	}
2003 }
2004 /* }}} */
2005 
2006 /* {{{ proto array ibase_field_info(resource query_result, int field_number)
2007    Get information about a field */
PHP_FUNCTION(ibase_field_info)2008 PHP_FUNCTION(ibase_field_info)
2009 {
2010 	zval *result_arg;
2011 	long field_arg;
2012 	int type;
2013 	XSQLDA *sqlda;
2014 
2015 	RESET_ERRMSG;
2016 
2017 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result_arg, &field_arg) == FAILURE) {
2018 		return;
2019 	}
2020 
2021 	zend_list_find(Z_RESVAL_P(result_arg), &type);
2022 
2023 	if (type == le_query) {
2024 		ibase_query *ib_query;
2025 
2026 		ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result_arg, -1, LE_QUERY, le_query);
2027 		sqlda = ib_query->out_sqlda;
2028 	} else {
2029 		ibase_result *ib_result;
2030 
2031 		ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
2032 		sqlda = ib_result->out_sqlda;
2033 	}
2034 
2035 	if (sqlda == NULL) {
2036 		_php_ibase_module_error("Trying to get field info from a non-select query" TSRMLS_CC);
2037 		RETURN_FALSE;
2038 	}
2039 
2040 	if (field_arg < 0 || field_arg >= sqlda->sqld) {
2041 		RETURN_FALSE;
2042 	}
2043 	_php_ibase_field_info(return_value, sqlda->sqlvar + field_arg);
2044 }
2045 /* }}} */
2046 
2047 /* {{{ proto int ibase_num_params(resource query)
2048    Get the number of params in a prepared query */
PHP_FUNCTION(ibase_num_params)2049 PHP_FUNCTION(ibase_num_params)
2050 {
2051 	zval *result;
2052 	ibase_query *ib_query;
2053 
2054 	RESET_ERRMSG;
2055 
2056 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
2057 		return;
2058 	}
2059 
2060 	ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result, -1, LE_QUERY, le_query);
2061 
2062 	if (ib_query->in_sqlda == NULL) {
2063 		RETURN_LONG(0);
2064 	} else {
2065 		RETURN_LONG(ib_query->in_sqlda->sqld);
2066 	}
2067 }
2068 /* }}} */
2069 
2070 /* {{{ proto array ibase_param_info(resource query, int field_number)
2071    Get information about a parameter */
PHP_FUNCTION(ibase_param_info)2072 PHP_FUNCTION(ibase_param_info)
2073 {
2074 	zval *result_arg;
2075 	long field_arg;
2076 	ibase_query *ib_query;
2077 
2078 	RESET_ERRMSG;
2079 
2080 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result_arg, &field_arg) == FAILURE) {
2081 		return;
2082 	}
2083 
2084 	ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result_arg, -1, LE_QUERY, le_query);
2085 
2086 	if (ib_query->in_sqlda == NULL) {
2087 		RETURN_FALSE;
2088 	}
2089 
2090 	if (field_arg < 0 || field_arg >= ib_query->in_sqlda->sqld) {
2091 		RETURN_FALSE;
2092 	}
2093 
2094 	_php_ibase_field_info(return_value,ib_query->in_sqlda->sqlvar + field_arg);
2095 }
2096 /* }}} */
2097 
2098 #endif /* HAVE_IBASE */
2099 
2100 /*
2101  * Local variables:
2102  * tab-width: 4
2103  * c-basic-offset: 4
2104  * End:
2105  * vim600: sw=4 ts=4 fdm=marker
2106  * vim<600: sw=4 ts=4
2107  */
2108