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

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