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