Annotation of embedaddon/php/ext/interbase/ibase_query.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 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: ibase_query.c 321634 2012-01-01 13:15:04Z felipe $ */
! 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:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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 */
! 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:
! 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:
! 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:
! 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:
! 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 */
! 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 */
! 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
! 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:
! 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:
! 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:
! 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 */
! 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 */
! 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 */
! 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 */
! 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 */
! 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 */
! 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 */
! 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 */
! 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 */
! 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:
! 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 */
! 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 */
! 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 */
! 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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>