1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl> | 16 +----------------------------------------------------------------------+ 17 */ 18 19/* $Id$ */ 20 21#ifdef HAVE_CONFIG_H 22#include "config.h" 23#endif 24 25#include "php.h" 26#include "php_ini.h" 27 28#if HAVE_IBASE 29 30#include "ext/standard/php_standard.h" 31#include "php_interbase.h" 32#include "php_ibase_includes.h" 33 34#define ISC_LONG_MIN INT_MIN 35#define ISC_LONG_MAX INT_MAX 36 37#define QUERY_RESULT 1 38#define EXECUTE_RESULT 2 39 40#define FETCH_ROW 1 41#define FETCH_ARRAY 2 42 43typedef 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 49typedef 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 60typedef 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 75typedef 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 */ 83typedef 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 96static int le_result, le_query; 97 98#define LE_RESULT "Firebird/InterBase result" 99#define LE_QUERY "Firebird/InterBase query" 100 101static 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 121static 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 139static 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 157static 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 185static 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 197void 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 206static 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 */ 317static 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 435static 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 639static 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 811static 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 864static 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 */ 1061PHP_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 */ 1203PHP_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 1240PHP_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 1295static 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 1396format_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 1432static 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 1481static 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 */ 1664PHP_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 */ 1672PHP_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 */ 1680PHP_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 */ 1693PHP_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 */ 1719PHP_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 */ 1738PHP_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 */ 1788PHP_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 */ 1866PHP_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 */ 1885PHP_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 1919static 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 */ 2008PHP_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 */ 2049PHP_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 */ 2072PHP_FUNCTION(ibase_param_info) 2073{ 2074 zval *result_arg; 2075 long field_arg; 2076 ibase_query *ib_query; 2077 2078 RESET_ERRMSG; 2079 2080 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result_arg, &field_arg) == FAILURE) { 2081 return; 2082 } 2083 2084 ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result_arg, -1, LE_QUERY, le_query); 2085 2086 if (ib_query->in_sqlda == NULL) { 2087 RETURN_FALSE; 2088 } 2089 2090 if (field_arg < 0 || field_arg >= ib_query->in_sqlda->sqld) { 2091 RETURN_FALSE; 2092 } 2093 2094 _php_ibase_field_info(return_value,ib_query->in_sqlda->sqlvar + field_arg); 2095} 2096/* }}} */ 2097 2098#endif /* HAVE_IBASE */ 2099 2100/* 2101 * Local variables: 2102 * tab-width: 4 2103 * c-basic-offset: 4 2104 * End: 2105 * vim600: sw=4 ts=4 fdm=marker 2106 * vim<600: sw=4 ts=4 2107 */ 2108