root/ext/interbase/ibase_query.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _php_ibase_free_xsqlda
  2. _php_ibase_free_stmt_handle
  3. _php_ibase_free_result
  4. _php_ibase_free_query
  5. php_ibase_free_query_rsrc
  6. php_ibase_query_minit
  7. _php_ibase_alloc_array
  8. _php_ibase_alloc_query
  9. _php_ibase_bind_array
  10. _php_ibase_bind
  11. _php_ibase_alloc_xsqlda
  12. _php_ibase_exec
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. _php_ibase_var_zval
  17. _php_ibase_arr_zval
  18. _php_ibase_fetch_hash
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. _php_ibase_field_info
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */