Back to index

php5  5.3.10
ibase_query.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl>              |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: ibase_query.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 
00028 #if HAVE_IBASE
00029 
00030 #include "ext/standard/php_standard.h"
00031 #include "php_interbase.h"
00032 #include "php_ibase_includes.h"
00033 
00034 #define ISC_LONG_MIN        INT_MIN
00035 #define ISC_LONG_MAX        INT_MAX
00036 
00037 #define QUERY_RESULT 1
00038 #define EXECUTE_RESULT      2
00039 
00040 #define FETCH_ROW           1
00041 #define FETCH_ARRAY         2
00042 
00043 typedef struct {
00044        ISC_ARRAY_DESC ar_desc;
00045        ISC_LONG ar_size; /* size of entire array in bytes */
00046        unsigned short el_type, el_size;
00047 } ibase_array;
00048 
00049 typedef struct {
00050        ibase_db_link *link;
00051        ibase_trans *trans;
00052        struct _ib_query *query;
00053        isc_stmt_handle stmt;
00054        unsigned short type;
00055        unsigned char has_more_rows, statement_type;
00056        XSQLDA *out_sqlda;
00057        ibase_array out_array[1]; /* last member */
00058 } ibase_result;
00059 
00060 typedef struct _ib_query {
00061        ibase_db_link *link;
00062        ibase_trans *trans;
00063        ibase_result *result;
00064        int result_res_id;
00065        isc_stmt_handle stmt;
00066        XSQLDA *in_sqlda, *out_sqlda;
00067        ibase_array *in_array, *out_array;
00068        unsigned short in_array_cnt, out_array_cnt;
00069        unsigned short dialect;
00070        char statement_type;
00071        char *query;
00072        long trans_res_id;
00073 } ibase_query;
00074 
00075 typedef struct {
00076        unsigned short vary_length;
00077        char vary_string[1];
00078 } IBVARY;
00079 
00080 /* sql variables union 
00081  * used for convert and binding input variables
00082  */
00083 typedef struct {
00084        union {
00085               short sval;
00086               float fval;
00087               ISC_LONG lval;
00088               ISC_QUAD qval;
00089               ISC_TIMESTAMP tsval;
00090               ISC_DATE dtval;
00091               ISC_TIME tmval;
00092        } val;
00093        short sqlind;
00094 } BIND_BUF;
00095 
00096 static int le_result, le_query;
00097 
00098 #define LE_RESULT "Firebird/InterBase result"
00099 #define LE_QUERY "Firebird/InterBase query"
00100 
00101 static void _php_ibase_free_xsqlda(XSQLDA *sqlda) /* {{{ */
00102 {
00103        int i;
00104        XSQLVAR *var;
00105 
00106        IBDEBUG("Free XSQLDA?");
00107        if (sqlda) {
00108               IBDEBUG("Freeing XSQLDA...");
00109               var = sqlda->sqlvar;
00110               for (i = 0; i < sqlda->sqld; i++, var++) {
00111                      efree(var->sqldata);
00112                      if (var->sqlind) {
00113                             efree(var->sqlind);
00114                      }
00115               }
00116               efree(sqlda);
00117        }
00118 }
00119 /* }}} */
00120 
00121 static void _php_ibase_free_stmt_handle(ibase_db_link *link, isc_stmt_handle stmt TSRMLS_DC) /* {{{ */
00122 {
00123        static char info[] = { isc_info_base_level, isc_info_end };
00124 
00125        if (stmt) {
00126               char res_buf[8];
00127               IBDEBUG("Dropping statement handle (free_stmt_handle)...");
00128               /* Only free statement if db-connection is still open */
00129               if (SUCCESS == isc_database_info(IB_STATUS, &link->handle, 
00130                                                  sizeof(info), info, sizeof(res_buf), res_buf)) {
00131                      if (isc_dsql_free_statement(IB_STATUS, &stmt, DSQL_drop)) {
00132                             _php_ibase_error(TSRMLS_C);
00133                      }
00134               }
00135        }
00136 }
00137 /* }}} */
00138 
00139 static void _php_ibase_free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00140 {
00141        ibase_result *ib_result = (ibase_result *) rsrc->ptr;
00142 
00143        IBDEBUG("Freeing result by dtor...");
00144        if (ib_result) {
00145               _php_ibase_free_xsqlda(ib_result->out_sqlda);
00146               if (ib_result->query != NULL) {
00147                      IBDEBUG("query still valid; don't drop statement handle");
00148                      ib_result->query->result = NULL;   /* Indicate to query, that result is released */
00149               } else {
00150                      _php_ibase_free_stmt_handle(ib_result->link, ib_result->stmt TSRMLS_CC);
00151               }
00152               efree(ib_result);
00153        }
00154 }
00155 /* }}} */
00156 
00157 static void _php_ibase_free_query(ibase_query *ib_query TSRMLS_DC) /* {{{ */
00158 {
00159        IBDEBUG("Freeing query...");
00160 
00161        if (ib_query->in_sqlda) {
00162               efree(ib_query->in_sqlda);
00163        }
00164        if (ib_query->out_sqlda) {
00165               efree(ib_query->out_sqlda);
00166        }
00167        if (ib_query->result != NULL) {
00168               IBDEBUG("result still valid; don't drop statement handle");
00169               ib_query->result->query = NULL;    /* Indicate to result, that query is released */
00170        } else {
00171               _php_ibase_free_stmt_handle(ib_query->link, ib_query->stmt TSRMLS_CC);
00172        }
00173        if (ib_query->in_array) {
00174               efree(ib_query->in_array);
00175        }
00176        if (ib_query->out_array) {
00177               efree(ib_query->out_array);
00178        }
00179        if (ib_query->query) {
00180               efree(ib_query->query);
00181        }
00182 }
00183 /* }}} */
00184 
00185 static void php_ibase_free_query_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00186 {
00187        ibase_query *ib_query = (ibase_query *)rsrc->ptr;
00188 
00189        if (ib_query != NULL) {
00190               IBDEBUG("Preparing to free query by dtor...");
00191               _php_ibase_free_query(ib_query TSRMLS_CC);
00192               efree(ib_query);
00193        }
00194 }
00195 /* }}} */
00196 
00197 void php_ibase_query_minit(INIT_FUNC_ARGS) /* {{{ */
00198 {
00199        le_result = zend_register_list_destructors_ex(_php_ibase_free_result, NULL, 
00200            "interbase result", module_number);
00201        le_query = zend_register_list_destructors_ex(php_ibase_free_query_rsrc, NULL, 
00202            "interbase query", module_number);
00203 }
00204 /* }}} */
00205 
00206 static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ */
00207        isc_db_handle link, isc_tr_handle trans, unsigned short *array_cnt TSRMLS_DC)
00208 {
00209        unsigned short i, n;
00210        ibase_array *ar;
00211 
00212        /* first check if we have any arrays at all */
00213        for (i = *array_cnt = 0; i < sqlda->sqld; ++i) {
00214               if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_ARRAY) {
00215                      ++*array_cnt;
00216               }
00217        }
00218        if (! *array_cnt) return SUCCESS;
00219 
00220        ar = safe_emalloc(sizeof(ibase_array), *array_cnt, 0);
00221 
00222        for (i = n = 0; i < sqlda->sqld; ++i) {
00223               unsigned short dim;
00224               unsigned long ar_size = 1;
00225               XSQLVAR *var = &sqlda->sqlvar[i];
00226 
00227               if ((var->sqltype & ~1) == SQL_ARRAY) {
00228                      ibase_array *a = &ar[n++];
00229                      ISC_ARRAY_DESC *ar_desc = &a->ar_desc;
00230 
00231                      if (isc_array_lookup_bounds(IB_STATUS, &link, &trans, var->relname,
00232                                    var->sqlname, ar_desc)) {
00233                             _php_ibase_error(TSRMLS_C);
00234                             efree(ar);
00235                             return FAILURE;
00236                      }
00237 
00238                      switch (ar_desc->array_desc_dtype) {
00239                             case blr_text:
00240                             case blr_text2:
00241                                    a->el_type = SQL_TEXT;
00242                                    a->el_size = ar_desc->array_desc_length;
00243                                    break;
00244                             case blr_short:
00245                                    a->el_type = SQL_SHORT;
00246                                    a->el_size = sizeof(short);
00247                                    break;
00248                             case blr_long:
00249                                    a->el_type = SQL_LONG;
00250                                    a->el_size = sizeof(ISC_LONG);
00251                                    break;
00252                             case blr_float:
00253                                    a->el_type = SQL_FLOAT;
00254                                    a->el_size = sizeof(float);
00255                                    break;
00256                             case blr_double:
00257                                    a->el_type = SQL_DOUBLE;
00258                                    a->el_size = sizeof(double);
00259                                    break;
00260                             case blr_int64:
00261                                    a->el_type = SQL_INT64;
00262                                    a->el_size = sizeof(ISC_INT64);
00263                                    break;
00264                             case blr_timestamp:
00265                                    a->el_type = SQL_TIMESTAMP;
00266                                    a->el_size = sizeof(ISC_TIMESTAMP);
00267                                    break;
00268                             case blr_sql_date:
00269                                    a->el_type = SQL_TYPE_DATE;
00270                                    a->el_size = sizeof(ISC_DATE);
00271                                    break;
00272                             case blr_sql_time:
00273                                    a->el_type = SQL_TYPE_TIME;
00274                                    a->el_size = sizeof(ISC_TIME);
00275                                    break;
00276                             case blr_varying:
00277                             case blr_varying2:
00283                                    a->el_type = SQL_TEXT;
00284                                    a->el_size = ar_desc->array_desc_length + sizeof(short);
00285                                    break;
00286                             case blr_quad:
00287                             case blr_blob_id:
00288                             case blr_cstring:
00289                             case blr_cstring2:
00296                             default:
00297                                    _php_ibase_module_error("Unsupported array type %d in relation '%s' column '%s'"
00298                                           TSRMLS_CC, ar_desc->array_desc_dtype, var->relname, var->sqlname);
00299                                    efree(ar);
00300                                    return FAILURE;
00301                      } /* switch array_desc_type */
00302 
00303                      /* calculate elements count */
00304                      for (dim = 0; dim < ar_desc->array_desc_dimensions; dim++) {
00305                             ar_size *= 1 + ar_desc->array_desc_bounds[dim].array_bound_upper
00306                                    -ar_desc->array_desc_bounds[dim].array_bound_lower;
00307                      }
00308                      a->ar_size = a->el_size * ar_size;
00309               } /* if SQL_ARRAY */
00310        } /* for column */
00311        *ib_arrayp = ar;
00312        return SUCCESS;
00313 }
00314 /* }}} */
00315 
00316 /* allocate and prepare query */
00317 static int _php_ibase_alloc_query(ibase_query *ib_query, ibase_db_link *link, /* {{{ */
00318        ibase_trans *trans, char *query, unsigned short dialect, int trans_res_id TSRMLS_DC)
00319 {
00320        static char info_type[] = {isc_info_sql_stmt_type};
00321        char result[8];
00322 
00323        /* Return FAILURE, if querystring is empty */
00324        if (*query == '\0') {
00325               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Querystring empty.");
00326               return FAILURE;
00327        }
00328 
00329        ib_query->link = link;
00330        ib_query->trans = trans;
00331        ib_query->result_res_id = 0;
00332        ib_query->result = NULL;
00333        ib_query->stmt = NULL;
00334        ib_query->in_array = NULL;
00335        ib_query->out_array = NULL;
00336        ib_query->dialect = dialect;
00337        ib_query->query = estrdup(query);
00338        ib_query->trans_res_id = trans_res_id;
00339        ib_query->out_sqlda = NULL;
00340        ib_query->in_sqlda = NULL;
00341 
00342        if (isc_dsql_allocate_statement(IB_STATUS, &link->handle, &ib_query->stmt)) {
00343               _php_ibase_error(TSRMLS_C);
00344               goto _php_ibase_alloc_query_error;
00345        }
00346 
00347        ib_query->out_sqlda = (XSQLDA *) emalloc(XSQLDA_LENGTH(1));
00348        ib_query->out_sqlda->sqln = 1;
00349        ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION;
00350 
00351        if (isc_dsql_prepare(IB_STATUS, &ib_query->trans->handle, &ib_query->stmt,
00352                      0, query, dialect, ib_query->out_sqlda)) {
00353               _php_ibase_error(TSRMLS_C);
00354               goto _php_ibase_alloc_query_error;
00355        }
00356 
00357        /* find out what kind of statement was prepared */
00358        if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_type), 
00359                      info_type, sizeof(result), result)) {
00360               _php_ibase_error(TSRMLS_C);
00361               goto _php_ibase_alloc_query_error;
00362        }
00363        ib_query->statement_type = result[3];     
00364 
00365        /* not enough output variables ? */
00366        if (ib_query->out_sqlda->sqld > ib_query->out_sqlda->sqln) {
00367               ib_query->out_sqlda = erealloc(ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
00368               ib_query->out_sqlda->sqln = ib_query->out_sqlda->sqld;
00369               ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION;
00370               if (isc_dsql_describe(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->out_sqlda)) {
00371                      _php_ibase_error(TSRMLS_C);
00372                      goto _php_ibase_alloc_query_error;
00373               }
00374        }
00375 
00376        /* maybe have input placeholders? */
00377        ib_query->in_sqlda = emalloc(XSQLDA_LENGTH(1));
00378        ib_query->in_sqlda->sqln = 1;
00379        ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION;
00380        if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) {
00381               _php_ibase_error(TSRMLS_C);
00382               goto _php_ibase_alloc_query_error;
00383        }
00384 
00385        /* not enough input variables ? */
00386        if (ib_query->in_sqlda->sqln < ib_query->in_sqlda->sqld) {
00387               ib_query->in_sqlda = erealloc(ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
00388               ib_query->in_sqlda->sqln = ib_query->in_sqlda->sqld;
00389               ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION;
00390 
00391               if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt,
00392                             SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) {
00393                      _php_ibase_error(TSRMLS_C);
00394                      goto _php_ibase_alloc_query_error;
00395               }
00396        }
00397 
00398        /* no, haven't placeholders at all */
00399        if (ib_query->in_sqlda->sqld == 0) {
00400               efree(ib_query->in_sqlda);
00401               ib_query->in_sqlda = NULL;
00402        } else if (FAILURE == _php_ibase_alloc_array(&ib_query->in_array, ib_query->in_sqlda,
00403                      link->handle, trans->handle, &ib_query->in_array_cnt TSRMLS_CC)) {
00404               goto _php_ibase_alloc_query_error;
00405        }
00406 
00407        if (ib_query->out_sqlda->sqld == 0) {
00408               efree(ib_query->out_sqlda);
00409               ib_query->out_sqlda = NULL;
00410        } else        if (FAILURE == _php_ibase_alloc_array(&ib_query->out_array, ib_query->out_sqlda,
00411                      link->handle, trans->handle, &ib_query->out_array_cnt TSRMLS_CC)) {
00412               goto _php_ibase_alloc_query_error;
00413        }
00414 
00415        return SUCCESS;
00416 
00417 _php_ibase_alloc_query_error:
00418 
00419        if (ib_query->out_sqlda) {
00420               efree(ib_query->out_sqlda);
00421        }
00422        if (ib_query->in_sqlda) {
00423               efree(ib_query->in_sqlda);
00424        }
00425        if (ib_query->out_array) {
00426               efree(ib_query->out_array);
00427        }
00428        if (ib_query->query) {
00429               efree(ib_query->query);
00430        }
00431        return FAILURE;
00432 }
00433 /* }}} */
00434 
00435 static int _php_ibase_bind_array(zval *val, char *buf, unsigned long buf_size, /* {{{ */
00436        ibase_array *array, int dim TSRMLS_DC)
00437 {
00438        zval null_val, *pnull_val = &null_val;
00439        int u_bound = array->ar_desc.array_desc_bounds[dim].array_bound_upper,
00440               l_bound = array->ar_desc.array_desc_bounds[dim].array_bound_lower,
00441               dim_len = 1 + u_bound - l_bound;
00442 
00443        ZVAL_NULL(pnull_val);
00444 
00445        if (dim < array->ar_desc.array_desc_dimensions) {
00446               unsigned long slice_size = buf_size / dim_len;
00447               unsigned short i;
00448               zval **subval = &val;
00449 
00450               if (Z_TYPE_P(val) == IS_ARRAY) {
00451                      zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
00452               }
00453 
00454               for (i = 0; i < dim_len; ++i) { 
00455 
00456                      if (Z_TYPE_P(val) == IS_ARRAY &&
00457                             zend_hash_get_current_data(Z_ARRVAL_P(val), (void *) &subval) == FAILURE)
00458                      {
00459                             subval = &pnull_val;
00460                      }
00461 
00462                      if (_php_ibase_bind_array(*subval, buf, slice_size, array, dim+1 TSRMLS_CC) == FAILURE)
00463                      {
00464                             return FAILURE;
00465                      }
00466                      buf += slice_size;
00467 
00468                      if (Z_TYPE_P(val) == IS_ARRAY) {
00469                             zend_hash_move_forward(Z_ARRVAL_P(val));
00470                      }
00471               }
00472 
00473               if (Z_TYPE_P(val) == IS_ARRAY) {
00474                      zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
00475               }
00476 
00477        } else {
00478               /* expect a single value */
00479               if (Z_TYPE_P(val) == IS_NULL) {
00480                      memset(buf, 0, buf_size);
00481               } else if (array->ar_desc.array_desc_scale < 0) {
00482 
00483                      /* no coercion for array types */
00484                      double l;
00485 
00486                      convert_to_double(val);
00487 
00488                      if (Z_DVAL_P(val) > 0) {
00489                             l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) + .5;
00490                      } else {
00491                             l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) - .5;
00492                      }
00493 
00494                      switch (array->el_type) {
00495                             case SQL_SHORT:
00496                                    if (l > SHRT_MAX || l < SHRT_MIN) {
00497                                           _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
00498                                           return FAILURE;
00499                                    }
00500                                    *(short*) buf = (short) l;
00501                                    break;
00502                             case SQL_LONG:
00503                                    if (l > ISC_LONG_MAX || l < ISC_LONG_MIN) {
00504                                           _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
00505                                           return FAILURE;
00506                                    }
00507                                    *(ISC_LONG*) buf = (ISC_LONG) l;
00508                                    break;
00509                             case SQL_INT64:
00510                                    {
00511                                           long double l;
00512 
00513                                           convert_to_string(val);
00514 
00515                                           if (!sscanf(Z_STRVAL_P(val), "%Lf", &l)) {
00516                                                  _php_ibase_module_error("Cannot convert '%s' to long double"
00517                                                         TSRMLS_CC, Z_STRVAL_P(val));
00518                                                  return FAILURE;
00519                                           }
00520 
00521                                           if (l > 0) {
00522                                                  *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10, 
00523                                                         -array->ar_desc.array_desc_scale) + .5);
00524                                           } else {
00525                                                  *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10, 
00526                                                         -array->ar_desc.array_desc_scale) - .5);
00527                                           }
00528                                    }
00529                                    break;
00530                      }                    
00531               } else {
00532                      struct tm t = { 0, 0, 0, 0, 0, 0 };
00533 
00534                      switch (array->el_type) {
00535                             unsigned short n;
00536                             ISC_INT64 l;
00537 
00538                             case SQL_SHORT:
00539                                    convert_to_long(val);
00540                                    if (Z_LVAL_P(val) > SHRT_MAX || Z_LVAL_P(val) < SHRT_MIN) {
00541                                           _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
00542                                           return FAILURE;
00543                                    }
00544                                    *(short *) buf = (short) Z_LVAL_P(val);
00545                                    break;
00546                             case SQL_LONG:
00547                                    convert_to_long(val);
00548 #if (SIZEOF_LONG > 4)
00549                                    if (Z_LVAL_P(val) > ISC_LONG_MAX || Z_LVAL_P(val) < ISC_LONG_MIN) {
00550                                           _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
00551                                           return FAILURE;
00552                                    }
00553 #endif
00554                                    *(ISC_LONG *) buf = (ISC_LONG) Z_LVAL_P(val);
00555                                    break;
00556                             case SQL_INT64:
00557 #if (SIZEOF_LONG >= 8)
00558                                    convert_to_long(val);
00559                                    *(long *) buf = Z_LVAL_P(val);
00560 #else
00561                                    convert_to_string(val);
00562                                    if (!sscanf(Z_STRVAL_P(val), "%" LL_MASK "d", &l)) {
00563                                           _php_ibase_module_error("Cannot convert '%s' to long integer"
00564                                                  TSRMLS_CC, Z_STRVAL_P(val));
00565                                           return FAILURE;
00566                                    } else {
00567                                           *(ISC_INT64 *) buf = l;
00568                                    }
00569 #endif
00570                                    break;
00571                             case SQL_FLOAT:
00572                                    convert_to_double(val);
00573                                    *(float*) buf = (float) Z_DVAL_P(val);
00574                                    break;
00575                             case SQL_DOUBLE:
00576                                    convert_to_double(val);
00577                                    *(double*) buf = Z_DVAL_P(val);
00578                                    break;
00579                             case SQL_TIMESTAMP:
00580                                    convert_to_string(val);
00581 #ifdef HAVE_STRPTIME
00582                                    strptime(Z_STRVAL_P(val), INI_STR("ibase.timestampformat"), &t);
00583 #else
00584                                    n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d", 
00585                                           &t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec);
00586 
00587                                    if (n != 3 && n != 6) {
00588                                           _php_ibase_module_error("Invalid date/time format (expected 3 or 6 fields, got %d."
00589                                                  " Use format 'm/d/Y H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
00590                                           return FAILURE;
00591                                    }
00592                                    t.tm_year -= 1900;
00593                                    t.tm_mon--;
00594 #endif
00595                                    isc_encode_timestamp(&t, (ISC_TIMESTAMP * ) buf);
00596                                    break;
00597                             case SQL_TYPE_DATE:
00598                                    convert_to_string(val);
00599 #ifdef HAVE_STRPTIME
00600                                    strptime(Z_STRVAL_P(val), INI_STR("ibase.dateformat"), &t);
00601 #else
00602                                    n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d", &t.tm_mon, &t.tm_mday, &t.tm_year);
00603 
00604                                    if (n != 3) {
00605                                           _php_ibase_module_error("Invalid date format (expected 3 fields, got %d. "
00606                                                  "Use format 'm/d/Y' You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
00607                                           return FAILURE;
00608                                    }
00609                                    t.tm_year -= 1900;
00610                                    t.tm_mon--;
00611 #endif
00612                                    isc_encode_sql_date(&t, (ISC_DATE *) buf);
00613                                    break;
00614                             case SQL_TYPE_TIME:
00615                                    convert_to_string(val);
00616 #ifdef HAVE_STRPTIME
00617                                    strptime(Z_STRVAL_P(val), INI_STR("ibase.timeformat"), &t);
00618 #else
00619                                    n = sscanf(Z_STRVAL_P(val), "%d%*[:]%d%*[:]%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
00620 
00621                                    if (n != 3) {
00622                                           _php_ibase_module_error("Invalid time format (expected 3 fields, got %d. "
00623                                                  "Use format 'H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
00624                                           return FAILURE;
00625                                    }
00626 #endif
00627                                    isc_encode_sql_time(&t, (ISC_TIME *) buf);
00628                                    break;
00629                             default:
00630                                    convert_to_string(val);
00631                                    strlcpy(buf, Z_STRVAL_P(val), buf_size);
00632                      }
00633               }
00634        }
00635        return SUCCESS;
00636 }             
00637 /* }}} */
00638 
00639 static int _php_ibase_bind(XSQLDA *sqlda, zval ***b_vars, BIND_BUF *buf, /* {{{ */
00640        ibase_query *ib_query TSRMLS_DC)
00641 {
00642        int i, array_cnt = 0, rv = SUCCESS;
00643 
00644        for (i = 0; i < sqlda->sqld; ++i) { /* bound vars */
00645 
00646               zval *b_var = *b_vars[i];
00647               XSQLVAR *var = &sqlda->sqlvar[i];
00648 
00649               var->sqlind = &buf[i].sqlind;
00650 
00651               /* check if a NULL should be inserted */
00652               switch (Z_TYPE_P(b_var)) {
00653                      int force_null;
00654 
00655                      case IS_STRING:
00656 
00657                             force_null = 0;
00658 
00659                             /* for these types, an empty string can be handled like a NULL value */
00660                             switch (var->sqltype & ~1) {
00661                                    case SQL_SHORT:
00662                                    case SQL_LONG:
00663                                    case SQL_INT64:
00664                                    case SQL_FLOAT:
00665                                    case SQL_DOUBLE:
00666                                    case SQL_TIMESTAMP:
00667                                    case SQL_TYPE_DATE:
00668                                    case SQL_TYPE_TIME:
00669                                           force_null = (Z_STRLEN_P(b_var) == 0);
00670                             }
00671 
00672                             if (! force_null) break;
00673 
00674                      case IS_NULL:
00675                                    buf[i].sqlind = -1;
00676 
00677                             if (var->sqltype & SQL_ARRAY) ++array_cnt;
00678 
00679                             continue;
00680               }
00681 
00682               /* if we make it to this point, we must provide a value for the parameter */
00683 
00684               buf[i].sqlind = 0;
00685 
00686               var->sqldata = (void*)&buf[i].val;
00687 
00688               switch (var->sqltype & ~1) {
00689                      struct tm t;
00690 
00691                      case SQL_TIMESTAMP:
00692                      case SQL_TYPE_DATE:
00693                      case SQL_TYPE_TIME:
00694                             if (Z_TYPE_P(b_var) == IS_LONG) {
00695                                    struct tm *res;
00696                                    res = php_gmtime_r(&Z_LVAL_P(b_var), &t);
00697                                    if (!res) {
00698                                           return FAILURE;
00699                                    }
00700                             } else {
00701 #ifdef HAVE_STRPTIME
00702                                    char *format = INI_STR("ibase.timestampformat");
00703 
00704                                    convert_to_string(b_var);
00705 
00706                                    switch (var->sqltype & ~1) {
00707                                           case SQL_TYPE_DATE:
00708                                                  format = INI_STR("ibase.dateformat");
00709                                                  break;
00710                                           case SQL_TYPE_TIME:
00711                                                  format = INI_STR("ibase.timeformat");
00712                                    }
00713                                    if (!strptime(Z_STRVAL_P(b_var), format, &t)) {
00714                                           /* strptime() cannot handle it, so let IB have a try */
00715                                           break;
00716                                    }
00717 #else /* ifndef HAVE_STRPTIME */
00718                                    break; /* let IB parse it as a string */
00719 #endif
00720                             }
00721 
00722                             switch (var->sqltype & ~1) {
00723                                    default: /* == case SQL_TIMESTAMP */
00724                                           isc_encode_timestamp(&t, &buf[i].val.tsval);
00725                                           break;
00726                                    case SQL_TYPE_DATE:
00727                                           isc_encode_sql_date(&t, &buf[i].val.dtval);
00728                                           break;
00729                                    case SQL_TYPE_TIME:
00730                                           isc_encode_sql_time(&t, &buf[i].val.tmval);
00731                                           break;
00732                             }
00733                             continue;
00734 
00735                      case SQL_BLOB:
00736 
00737                             convert_to_string(b_var);
00738 
00739                             if (Z_STRLEN_P(b_var) != BLOB_ID_LEN ||
00740                                    !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) {
00741 
00742                                    ibase_blob ib_blob = { NULL, BLOB_INPUT };
00743 
00744                                    if (isc_create_blob(IB_STATUS, &ib_query->link->handle,
00745                                                  &ib_query->trans->handle, &ib_blob.bl_handle, &ib_blob.bl_qd)) {
00746                                           _php_ibase_error(TSRMLS_C);
00747                                           return FAILURE;
00748                                    }
00749 
00750                                    if (_php_ibase_blob_add(&b_var, &ib_blob TSRMLS_CC) != SUCCESS) {
00751                                           return FAILURE;
00752                                    }
00753 
00754                                    if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
00755                                           _php_ibase_error(TSRMLS_C);
00756                                           return FAILURE;
00757                                    }
00758                                    buf[i].val.qval = ib_blob.bl_qd;
00759                             }
00760                             continue;
00761 
00762                      case SQL_ARRAY:
00763 
00764                             if (Z_TYPE_P(b_var) != IS_ARRAY) {
00765                                    convert_to_string(b_var);
00766 
00767                                    if (Z_STRLEN_P(b_var) != BLOB_ID_LEN ||
00768                                           !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) {
00769 
00770                                           _php_ibase_module_error("Parameter %d: invalid array ID" TSRMLS_CC,i+1);
00771                                           rv = FAILURE;
00772                                    }
00773                             } else {
00774                                    /* convert the array data into something IB can understand */
00775                                    ibase_array *ar = &ib_query->in_array[array_cnt];
00776                                    void *array_data = emalloc(ar->ar_size);
00777                                    ISC_QUAD array_id = { 0, 0 };
00778 
00779                                    if (FAILURE == _php_ibase_bind_array(b_var, array_data, ar->ar_size, 
00780                                                  ar, 0 TSRMLS_CC)) {
00781                                           _php_ibase_module_error("Parameter %d: failed to bind array argument"
00782                                                  TSRMLS_CC,i+1);
00783                                           efree(array_data);
00784                                           rv = FAILURE;
00785                                           continue;
00786                                    }
00787 
00788                                    if (isc_array_put_slice(IB_STATUS, &ib_query->link->handle, &ib_query->trans->handle, 
00789                                                  &array_id, &ar->ar_desc, array_data, &ar->ar_size)) {
00790                                           _php_ibase_error(TSRMLS_C);
00791                                           efree(array_data);
00792                                           return FAILURE;
00793                                    }
00794                                    buf[i].val.qval = array_id;
00795                                    efree(array_data);
00796                             }                           
00797                             ++array_cnt;
00798                             continue;
00799                      } /* switch */
00800 
00801                      /* we end up here if none of the switch cases handled the field */
00802                      convert_to_string(b_var);
00803                      var->sqldata = Z_STRVAL_P(b_var);
00804                      var->sqllen    = Z_STRLEN_P(b_var);
00805                      var->sqltype = SQL_TEXT;
00806        } /* for */
00807        return rv;
00808 }
00809 /* }}} */
00810 
00811 static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */
00812 {
00813        int i;
00814 
00815        for (i = 0; i < sqlda->sqld; i++) {
00816               XSQLVAR *var = &sqlda->sqlvar[i];
00817 
00818               switch (var->sqltype & ~1) {
00819                      case SQL_TEXT:
00820                             var->sqldata = safe_emalloc(sizeof(char), var->sqllen, 0);
00821                             break;
00822                      case SQL_VARYING:
00823                             var->sqldata = safe_emalloc(sizeof(char), var->sqllen + sizeof(short), 0);
00824                             break;
00825                      case SQL_SHORT:
00826                             var->sqldata = emalloc(sizeof(short));
00827                             break;
00828                      case SQL_LONG:
00829                             var->sqldata = emalloc(sizeof(ISC_LONG));
00830                             break;
00831                      case SQL_FLOAT:
00832                             var->sqldata = emalloc(sizeof(float));
00833                                    break;
00834                      case SQL_DOUBLE:
00835                             var->sqldata = emalloc(sizeof(double));
00836                             break;
00837                      case SQL_INT64:
00838                             var->sqldata = emalloc(sizeof(ISC_INT64));
00839                             break;
00840                      case SQL_TIMESTAMP:
00841                             var->sqldata = emalloc(sizeof(ISC_TIMESTAMP));
00842                             break;
00843                      case SQL_TYPE_DATE:
00844                             var->sqldata = emalloc(sizeof(ISC_DATE));
00845                             break;
00846                      case SQL_TYPE_TIME:
00847                             var->sqldata = emalloc(sizeof(ISC_TIME));
00848                             break;
00849                      case SQL_BLOB:
00850                      case SQL_ARRAY:
00851                             var->sqldata = emalloc(sizeof(ISC_QUAD));
00852                             break;
00853               } /* switch */
00854 
00855               if (var->sqltype & 1) { /* sql NULL flag */
00856                      var->sqlind = emalloc(sizeof(short));
00857               } else {
00858                      var->sqlind = NULL;
00859               }
00860        } /* for */
00861 }
00862 /* }}} */
00863 
00864 static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resultp, /* {{{ */
00865        ibase_query *ib_query, zval ***args)
00866 {
00867        XSQLDA *in_sqlda = NULL, *out_sqlda = NULL;
00868        BIND_BUF *bind_buf = NULL;
00869        int i, rv = FAILURE;
00870        static char info_count[] = { isc_info_sql_records };
00871        char result[64];
00872        ISC_STATUS isc_result;
00873        int argc = ib_query->in_sqlda ? ib_query->in_sqlda->sqld : 0;
00874        
00875        RESET_ERRMSG;
00876 
00877        for (i = 0; i < argc; ++i) {
00878               SEPARATE_ZVAL(args[i]);
00879        }
00880 
00881        switch (ib_query->statement_type) {
00882               isc_tr_handle tr;
00883               ibase_tr_list **l;
00884               ibase_trans *trans;
00885 
00886               case isc_info_sql_stmt_start_trans:
00887 
00888                      /* a SET TRANSACTION statement should be executed with a NULL trans handle */
00889                      tr = NULL;
00890 
00891                      if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, &tr, 0, 
00892                                    ib_query->query, ib_query->dialect, NULL)) {
00893                             _php_ibase_error(TSRMLS_C);
00894                             goto _php_ibase_exec_error;
00895                      }
00896 
00897                      trans = (ibase_trans *) emalloc(sizeof(ibase_trans));
00898                      trans->handle = tr;
00899                      trans->link_cnt = 1;
00900                      trans->affected_rows = 0;
00901                      trans->db_link[0] = ib_query->link;
00902 
00903                      if (ib_query->link->tr_list == NULL) {
00904                             ib_query->link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
00905                             ib_query->link->tr_list->trans = NULL;
00906                             ib_query->link->tr_list->next = NULL;
00907                      }
00908 
00909                      /* link the transaction into the connection-transaction list */
00910                      for (l = &ib_query->link->tr_list; *l != NULL; l = &(*l)->next);
00911                      *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
00912                      (*l)->trans = trans;
00913                      (*l)->next = NULL;
00914 
00915                      ZEND_REGISTER_RESOURCE(return_value, trans, le_trans);
00916 
00917                      return SUCCESS;
00918 
00919               case isc_info_sql_stmt_commit:
00920               case isc_info_sql_stmt_rollback:
00921 
00922                      if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, 
00923                                    &ib_query->trans->handle, 0, ib_query->query, ib_query->dialect, NULL)) {
00924                             _php_ibase_error(TSRMLS_C);
00925                             goto _php_ibase_exec_error;
00926                      }
00927 
00928                      if (ib_query->trans->handle == NULL && ib_query->trans_res_id != 0) {
00929                             /* transaction was released by the query and was a registered resource, 
00930                                so we have to release it */
00931                             zend_list_delete(ib_query->trans_res_id);
00932                      }
00933 
00934                      RETVAL_TRUE;
00935 
00936                      return SUCCESS;
00937 
00938               default:
00939                      RETVAL_FALSE;
00940        }
00941 
00942        /* allocate sqlda and output buffers */
00943        if (ib_query->out_sqlda) { /* output variables in select, select for update */
00944               ibase_result *res;
00945 
00946               IBDEBUG("Query wants XSQLDA for output");
00947               res = emalloc(sizeof(ibase_result)+sizeof(ibase_array)*max(0,ib_query->out_array_cnt-1));
00948               res->link = ib_query->link;
00949               res->trans = ib_query->trans;
00950               res->stmt = ib_query->stmt;
00951               /* ib_result and ib_query point at each other to handle release of statement handle properly */
00952               res->query = ib_query;
00953               ib_query->result = res;
00954               res->statement_type = ib_query->statement_type;
00955               res->has_more_rows = 1;
00956 
00957               out_sqlda = res->out_sqlda = emalloc(XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
00958               memcpy(out_sqlda, ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
00959               _php_ibase_alloc_xsqlda(out_sqlda);
00960 
00961               if (ib_query->out_array) {
00962                      memcpy(&res->out_array, ib_query->out_array, sizeof(ibase_array)*ib_query->out_array_cnt);
00963               }
00964               *ib_resultp = res;
00965        }
00966 
00967        if (ib_query->in_sqlda) { /* has placeholders */
00968               IBDEBUG("Query wants XSQLDA for input");
00969               in_sqlda = emalloc(XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
00970               memcpy(in_sqlda, ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
00971               bind_buf = safe_emalloc(sizeof(BIND_BUF), ib_query->in_sqlda->sqld, 0);
00972               if (_php_ibase_bind(in_sqlda, args, bind_buf, ib_query TSRMLS_CC) == FAILURE) {
00973                      IBDEBUG("Could not bind input XSQLDA");
00974                      goto _php_ibase_exec_error;
00975               }
00976        }
00977 
00978        if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) {
00979               isc_result = isc_dsql_execute2(IB_STATUS, &ib_query->trans->handle,
00980                      &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda, out_sqlda);
00981        } else {
00982               isc_result = isc_dsql_execute(IB_STATUS, &ib_query->trans->handle,
00983                      &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda);
00984        }
00985        if (isc_result) {
00986               IBDEBUG("Could not execute query");
00987               _php_ibase_error(TSRMLS_C);
00988               goto _php_ibase_exec_error;
00989        }
00990        ib_query->trans->affected_rows = 0;
00991 
00992        switch (ib_query->statement_type) {
00993 
00994               unsigned long affected_rows;
00995 
00996               case isc_info_sql_stmt_insert:
00997               case isc_info_sql_stmt_update:
00998               case isc_info_sql_stmt_delete:
00999               case isc_info_sql_stmt_exec_procedure:
01000 
01001                      if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_count),
01002                                    info_count, sizeof(result), result)) {
01003                             _php_ibase_error(TSRMLS_C);
01004                             goto _php_ibase_exec_error;
01005                      }
01006 
01007                      affected_rows = 0;
01008 
01009                      if (result[0] == isc_info_sql_records) {
01010                             unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
01011 
01012                             while (result[i] != isc_info_end && i < result_size) {
01013                                    short len = (short)isc_vax_integer(&result[i+1],2);
01014                                    if (result[i] != isc_info_req_select_count) {
01015                                           affected_rows += isc_vax_integer(&result[i+3],len);
01016                                    }
01017                                    i += len+3;
01018                             }
01019                      }
01020 
01021                      ib_query->trans->affected_rows = affected_rows;
01022 
01023                      if (!ib_query->out_sqlda) { /* no result set is being returned */
01024                             if (affected_rows) {
01025                                    RETVAL_LONG(affected_rows);
01026                             } else {
01027                                    RETVAL_TRUE;
01028                             }
01029                             break;
01030                      }
01031               default:
01032                      RETVAL_TRUE;
01033        }
01034 
01035        rv = SUCCESS;
01036 
01037 _php_ibase_exec_error:
01038 
01039        if (in_sqlda) {
01040               efree(in_sqlda);
01041        }
01042        if (bind_buf)
01043               efree(bind_buf);
01044 
01045        if (rv == FAILURE) {
01046               if (*ib_resultp) {
01047                      efree(*ib_resultp);
01048                      *ib_resultp = NULL;
01049               }
01050               if (out_sqlda) {
01051                      _php_ibase_free_xsqlda(out_sqlda);
01052               }
01053        }
01054 
01055        return rv;
01056 }
01057 /* }}} */
01058 
01059 /* {{{ proto mixed ibase_query([resource link_identifier, [ resource link_identifier, ]] string query [, mixed bind_arg [, mixed bind_arg [, ...]]])
01060    Execute a query */
01061 PHP_FUNCTION(ibase_query)
01062 {
01063        zval *zlink, *ztrans, ***bind_args = NULL;
01064        char *query;
01065        int bind_i, query_len, bind_num;
01066        long trans_res_id = 0;
01067        ibase_db_link *ib_link = NULL;
01068        ibase_trans *trans = NULL;
01069        ibase_query ib_query = { NULL, NULL, 0, 0 };
01070        ibase_result *result = NULL;
01071 
01072        RESET_ERRMSG;
01073        
01074        RETVAL_FALSE;
01075 
01076        switch (ZEND_NUM_ARGS()) {
01077               long l;
01078 
01079               default:
01080                   if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "rrs",
01081                                    &zlink, &ztrans, &query, &query_len)) {
01082 
01083                             ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, &zlink, -1, LE_LINK, le_link, le_plink);
01084                             ZEND_FETCH_RESOURCE(trans, ibase_trans*, &ztrans, -1, LE_TRANS,       le_trans);
01085                             
01086                             trans_res_id = Z_LVAL_P(ztrans);
01087                             bind_i = 3;
01088                             break;
01089                   }
01090               case 2:
01091                      if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "rs",
01092                                    &zlink, &query, &query_len)) {
01093                             _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &zlink, &ib_link, &trans);
01094        
01095                             if (trans != NULL) {
01096                                    trans_res_id = Z_LVAL_P(zlink);
01097                             }
01098                             bind_i = 2;
01099                             break;
01100                      }
01101 
01102                      /* the statement is 'CREATE DATABASE ...' if the link argument is IBASE_CREATE */
01103                      if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS()
01104                                    TSRMLS_CC, "ls", &l, &query, &query_len) && l == PHP_IBASE_CREATE) {
01105                             isc_db_handle db = NULL;
01106                             isc_tr_handle trans = NULL;
01107 
01108                             if (PG(sql_safe_mode)) {
01109                                    _php_ibase_module_error("CREATE DATABASE is not allowed in SQL safe mode"
01110                                           TSRMLS_CC);
01111 
01112                             } else if (((l = INI_INT("ibase.max_links")) != -1) && (IBG(num_links) >= l)) {
01113                                    _php_ibase_module_error("CREATE DATABASE is not allowed: maximum link count "
01114                                           "(%ld) reached" TSRMLS_CC, l);
01115 
01116                             } else if (isc_dsql_execute_immediate(IB_STATUS, &db, &trans, (short)query_len, 
01117                                           query, SQL_DIALECT_CURRENT, NULL)) {
01118                                    _php_ibase_error(TSRMLS_C);
01119 
01120                             } else if (!db) {
01121                                    _php_ibase_module_error("Connection to created database could not be "
01122                                           "established" TSRMLS_CC);
01123 
01124                             } else {
01125 
01126                                    /* register the link as a resource; unfortunately, we cannot register 
01127                                       it in the hash table, because we don't know the connection params */
01128                                    ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link));
01129                                    ib_link->handle = db;
01130                                    ib_link->dialect = SQL_DIALECT_CURRENT;
01131                                    ib_link->tr_list = NULL;
01132                                    ib_link->event_head = NULL;
01133 
01134                                    ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link);
01135                                    zend_list_addref(Z_LVAL_P(return_value));
01136                                    IBG(default_link) = Z_LVAL_P(return_value);
01137                                    ++IBG(num_links);
01138                             }
01139                             return;
01140                      }                                  
01141               case 1:
01142               case 0:
01143                      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() ? 1 : 0 TSRMLS_CC, "s", &query, 
01144                                    &query_len)) {
01145                             ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK,
01146                             le_link, le_plink);
01147 
01148                             bind_i = 1;
01149                             break;
01150                      }
01151                      return;
01152        }
01153 
01154        /* open default transaction */
01155        if (ib_link == NULL || FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC) 
01156                      || FAILURE == _php_ibase_alloc_query(&ib_query, ib_link, trans, query, ib_link->dialect,
01157                             trans_res_id TSRMLS_CC)) {
01158               return;
01159        }
01160 
01161        do {
01162               int bind_n = ZEND_NUM_ARGS() - bind_i,
01163                   expected_n = ib_query.in_sqlda ? ib_query.in_sqlda->sqld : 0;
01164               
01165               if (bind_n != expected_n) {
01166                      php_error_docref(NULL TSRMLS_CC, (bind_n < expected_n) ? E_WARNING : E_NOTICE,
01167                             "Statement expects %d arguments, %d given", expected_n, bind_n);
01168                      if (bind_n < expected_n) {
01169                             break;
01170                      }
01171               } else if (bind_n > 0) {           
01172                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &bind_args, &bind_num) == FAILURE) {
01173                             return;
01174                      }
01175               }
01176        
01177               if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, &ib_query, 
01178                             &bind_args[bind_i])) {
01179                      break;
01180               }
01181 
01182               if (result != NULL) { /* statement returns a result */
01183                      result->type = QUERY_RESULT;       
01184 
01185                      /* EXECUTE PROCEDURE returns only one row => statement can be released immediately */
01186                      if (ib_query.statement_type != isc_info_sql_stmt_exec_procedure) {
01187                             ib_query.stmt = NULL; /* keep stmt when free query */
01188                      }
01189                      ZEND_REGISTER_RESOURCE(return_value, result, le_result);
01190               }
01191        } while (0);
01192 
01193        _php_ibase_free_query(&ib_query TSRMLS_CC);
01194 
01195        if (bind_args) {
01196               efree(bind_args);
01197        }
01198 }
01199 /* }}} */
01200 
01201 /* {{{ proto int ibase_affected_rows( [ resource link_identifier ] )
01202    Returns the number of rows affected by the previous INSERT, UPDATE or DELETE statement */
01203 PHP_FUNCTION(ibase_affected_rows)
01204 {
01205        ibase_trans *trans = NULL;
01206        ibase_db_link *ib_link;
01207        zval *arg = NULL;
01208               
01209        RESET_ERRMSG;
01210        
01211        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg) == FAILURE) {
01212               return;
01213        }
01214 
01215        if (!arg) {
01216               ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
01217               if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
01218                      RETURN_FALSE;
01219               }
01220               trans = ib_link->tr_list->trans;
01221        } else {
01222               /* one id was passed, could be db or trans id */
01223               _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &arg, &ib_link, &trans);
01224               if (trans == NULL) {
01225                      ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &arg, -1, LE_LINK, le_link, le_plink);
01226 
01227                      if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
01228                             RETURN_FALSE;
01229                      }
01230                      trans = ib_link->tr_list->trans;
01231               }
01232        }
01233        RETURN_LONG(trans->affected_rows);
01234 }
01235 /* }}} */
01236 
01237 /* {{{ proto int ibase_num_rows( resource result_identifier ) 
01238    Return the number of rows that are available in a result */
01239 #if abies_0
01240 PHP_FUNCTION(ibase_num_rows) 
01241 {
01262        zval *result_arg;
01263        ibase_result *ib_result;
01264        static char info_count[] = {isc_info_sql_records};
01265        char result[64];
01266 
01267        RESET_ERRMSG;
01268 
01269        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result_arg) == FAILURE) {
01270               return;
01271        }
01272 
01273        ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
01274 
01275        if (isc_dsql_sql_info(IB_STATUS, &ib_result->stmt, sizeof(info_count), info_count, sizeof(result), result)) {
01276               _php_ibase_error(TSRMLS_C);
01277               RETURN_FALSE;
01278        }
01279 
01280        if (result[0] == isc_info_sql_records) {
01281               unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
01282 
01283               while (result[i] != isc_info_end && i < result_size) {
01284                      short len = (short)isc_vax_integer(&result[i+1],2);
01285                      if (result[i] == isc_info_req_select_count) {
01286                             RETURN_LONG(isc_vax_integer(&result[i+3],len));
01287                      }
01288                      i += len+3;
01289               }
01290        }                                  
01291 }
01292 #endif
01293 /* }}} */
01294 
01295 static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ */
01296        int scale, int flag TSRMLS_DC)
01297 {
01298        static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 
01299               10000, 
01300               100000, 
01301               1000000, 
01302               10000000,
01303               100000000, 
01304               1000000000, 
01305               LL_LIT(10000000000), 
01306               LL_LIT(100000000000),
01307               LL_LIT(1000000000000), 
01308               LL_LIT(10000000000000), 
01309               LL_LIT(100000000000000),
01310               LL_LIT(1000000000000000),
01311               LL_LIT(10000000000000000), 
01312               LL_LIT(100000000000000000), 
01313               LL_LIT(1000000000000000000)
01314        };
01315 
01316        switch (type & ~1) {
01317               unsigned short l;
01318               long n;
01319               char string_data[255];
01320               struct tm t;
01321               char *format;
01322 
01323               case SQL_VARYING:
01324                      len = ((IBVARY *) data)->vary_length;
01325                      data = ((IBVARY *) data)->vary_string;
01326                      /* no break */
01327               case SQL_TEXT:
01328                      if (PG(magic_quotes_runtime)) {
01329                             Z_STRVAL_P(val) = php_addslashes(data, len, &Z_STRLEN_P(val), 0 TSRMLS_CC);
01330                             Z_TYPE_P(val) = IS_STRING;
01331                      } else {
01332                             ZVAL_STRINGL(val,(char *) data,len,1);
01333                      }
01334                      break;
01335               case SQL_SHORT:
01336                      n = *(short *) data;
01337                      goto _sql_long;
01338               case SQL_INT64:
01339 #if (SIZEOF_LONG >= 8)
01340                      n = *(long *) data;
01341                      goto _sql_long;
01342 #else
01343                      if (scale == 0) {
01344                             l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d", *(ISC_INT64 *) data);
01345                             ZVAL_STRINGL(val,string_data,l,1);
01346                      } else {
01347                             ISC_INT64 n = *(ISC_INT64 *) data, f = scales[-scale];
01348 
01349                             if (n >= 0) {
01350                                    l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, n % f);
01351                             } else if (n <= -f) {
01352                                    l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, -n % f);                       
01353                              } else {
01354                                    l = slprintf(string_data, sizeof(string_data), "-0.%0*" LL_MASK "d", -scale, -n % f);
01355                             }
01356                             ZVAL_STRINGL(val,string_data,l,1);
01357                      }
01358                      break;
01359 #endif
01360               case SQL_LONG:
01361                      n = *(ISC_LONG *) data; 
01362               _sql_long:
01363                      if (scale == 0) {
01364                             ZVAL_LONG(val,n);
01365                      } else {
01366                             long f = (long) scales[-scale];
01367 
01368                             if (n >= 0) {
01369                                    l = slprintf(string_data, sizeof(string_data), "%ld.%0*ld", n / f, -scale,  n % f);
01370                             } else if (n <= -f) {
01371                                    l = slprintf(string_data, sizeof(string_data), "%ld.%0*ld", n / f, -scale,  -n % f);
01372                             } else {
01373                                    l = slprintf(string_data, sizeof(string_data), "-0.%0*ld", -scale, -n % f);
01374                             }
01375                             ZVAL_STRINGL(val,string_data,l,1);
01376                      }
01377                      break;
01378               case SQL_FLOAT:
01379                      ZVAL_DOUBLE(val, *(float *) data);
01380                      break;
01381               case SQL_DOUBLE:
01382                      ZVAL_DOUBLE(val, *(double *) data);
01383                      break;
01384               case SQL_DATE: /* == case SQL_TIMESTAMP: */
01385                      format = INI_STR("ibase.timestampformat");
01386                      isc_decode_timestamp((ISC_TIMESTAMP *) data, &t);
01387                      goto format_date_time;
01388               case SQL_TYPE_DATE:
01389                      format = INI_STR("ibase.dateformat");
01390                      isc_decode_sql_date((ISC_DATE *) data, &t);
01391                      goto format_date_time;
01392               case SQL_TYPE_TIME:
01393                      format = INI_STR("ibase.timeformat");
01394                      isc_decode_sql_time((ISC_TIME *) data, &t);
01395 
01396 format_date_time:
01397                      /*
01398                        XXX - Might have to remove this later - seems that isc_decode_date()
01399                         always sets tm_isdst to 0, sometimes incorrectly (InterBase 6 bug?)
01400                      */
01401                      t.tm_isdst = -1;
01402 #if HAVE_TM_ZONE
01403                      t.tm_zone = tzname[0];
01404 #endif
01405                      if (flag & PHP_IBASE_UNIXTIME) {
01406                             ZVAL_LONG(val, mktime(&t));
01407                      } else {
01408 #if HAVE_STRFTIME
01409                             l = strftime(string_data, sizeof(string_data), format, &t);
01410 #else
01411                             switch (type & ~1) {
01412                                    default:
01413                                           l = slprintf(string_data, sizeof(string_data), "%02d/%02d/%4d %02d:%02d:%02d", t.tm_mon+1, t.tm_mday, 
01414                                                  t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
01415                                           break;
01416                                    case SQL_TYPE_DATE:
01417                                           l = slprintf(string_data, sizeof(string_data), "%02d/%02d/%4d", t.tm_mon + 1, t.tm_mday, t.tm_year+1900);
01418                                           break;
01419                                    case SQL_TYPE_TIME:
01420                                           l = slprintf(string_data, sizeof(string_data), "%02d:%02d:%02d", t.tm_hour, t.tm_min, t.tm_sec);
01421                                           break;
01422                             }
01423 #endif
01424                             ZVAL_STRINGL(val,string_data,l,1);
01425                             break;
01426                      }
01427        } /* switch (type) */
01428        return SUCCESS;
01429 }
01430 /* }}} */
01431 
01432 static int _php_ibase_arr_zval(zval *ar_zval, char *data, unsigned long data_size, /* {{{ */
01433        ibase_array *ib_array, int dim, int flag TSRMLS_DC)
01434 {
01438        int 
01439               u_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_upper,
01440               l_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_lower,
01441               dim_len = 1 + u_bound - l_bound;
01442        unsigned short i;
01443 
01444        if (dim < ib_array->ar_desc.array_desc_dimensions) { /* array again */
01445               unsigned long slice_size = data_size / dim_len;
01446 
01447               array_init(ar_zval);
01448 
01449               for (i = 0; i < dim_len; ++i) {
01450                      zval *slice_zval;
01451                      ALLOC_INIT_ZVAL(slice_zval);
01452 
01453                      /* recursion here */
01454                      if (FAILURE == _php_ibase_arr_zval(slice_zval, data, slice_size, ib_array, dim + 1,
01455                                    flag TSRMLS_CC)) {
01456                             return FAILURE;
01457                      }
01458                      data += slice_size;
01459 
01460                      add_index_zval(ar_zval,l_bound+i,slice_zval);
01461               }
01462        } else { /* data at last */
01463 
01464               if (FAILURE == _php_ibase_var_zval(ar_zval, data, ib_array->el_type,
01465                             ib_array->ar_desc.array_desc_length, ib_array->ar_desc.array_desc_scale, flag TSRMLS_CC)) {
01466                      return FAILURE;
01467               }
01468 
01469               /* fix for peculiar handling of VARCHAR arrays;
01470                  truncate the field to the cstring length */
01471               if (ib_array->ar_desc.array_desc_dtype == blr_varying ||
01472                      ib_array->ar_desc.array_desc_dtype == blr_varying2) {
01473 
01474                      Z_STRLEN_P(ar_zval) = strlen(Z_STRVAL_P(ar_zval));
01475               }
01476        }
01477        return SUCCESS;
01478 }
01479 /* }}} */
01480 
01481 static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type) /* {{{ */
01482 {
01483        zval *result_arg;
01484        long i, array_cnt = 0, flag = 0;
01485        ibase_result *ib_result;
01486 
01487        RESET_ERRMSG;
01488 
01489        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result_arg, &flag)) {
01490               return;
01491        }
01492 
01493        ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
01494 
01495        if (ib_result->out_sqlda == NULL || !ib_result->has_more_rows) {
01496               RETURN_FALSE;
01497        }
01498 
01499        if (ib_result->statement_type != isc_info_sql_stmt_exec_procedure) {
01500               if (isc_dsql_fetch(IB_STATUS, &ib_result->stmt, 1, ib_result->out_sqlda)) {
01501                      ib_result->has_more_rows = 0;
01502                      if (IB_STATUS[0] && IB_STATUS[1]) { /* error in fetch */
01503                             _php_ibase_error(TSRMLS_C);
01504                      }
01505                      RETURN_FALSE;
01506               }
01507        } else {
01508               ib_result->has_more_rows = 0;
01509        }      
01510 
01511        array_init(return_value);
01512 
01513        for (i = 0; i < ib_result->out_sqlda->sqld; ++i) {
01514               XSQLVAR *var = &ib_result->out_sqlda->sqlvar[i];
01515               char buf[METADATALENGTH+4], *alias = var->aliasname;
01516               
01517               if (! (fetch_type & FETCH_ROW)) {
01518                      int i = 0;
01519                      char const *base = "FIELD"; /* use 'FIELD' if name is empty */
01520                      
01525                      switch (*alias) {
01526                             void *p;
01527                             
01528                             default:
01529                                    i = 1;
01530                                    base = alias;
01531                                    
01532                                    while (SUCCESS == zend_symtable_find(
01533                                                  Z_ARRVAL_P(return_value),alias,strlen(alias)+1,&p)) {
01534                             
01535                             case '\0':
01536                                           snprintf(alias = buf, sizeof(buf), "%s_%02d", base, i++);
01537                                    }
01538                      }
01539               }
01540 
01541               if (((var->sqltype & 1) == 0) || *var->sqlind != -1) {
01542                      zval *result;
01543                      ALLOC_INIT_ZVAL(result);
01544 
01545                      switch (var->sqltype & ~1) {
01546 
01547                             default:
01548                                    _php_ibase_var_zval(result, var->sqldata, var->sqltype, var->sqllen,
01549                                           var->sqlscale, flag TSRMLS_CC);
01550                                    break;
01551                             case SQL_BLOB:
01552                                    if (flag & PHP_IBASE_FETCH_BLOBS) { /* fetch blob contents into hash */
01553 
01554                                           ibase_blob blob_handle;
01555                                           unsigned long max_len = 0;
01556                                           static char bl_items[] = {isc_info_blob_total_length};
01557                                           char bl_info[20];
01558                                           unsigned short i;
01559 
01560                                           blob_handle.bl_handle = NULL;
01561                                           blob_handle.bl_qd = *(ISC_QUAD *) var->sqldata;
01562 
01563                                           if (isc_open_blob(IB_STATUS, &ib_result->link->handle, &ib_result->trans->handle,
01564                                                         &blob_handle.bl_handle, &blob_handle.bl_qd)) {
01565                                                  _php_ibase_error(TSRMLS_C);
01566                                                  goto _php_ibase_fetch_error;
01567                                           }
01568 
01569                                           if (isc_blob_info(IB_STATUS, &blob_handle.bl_handle, sizeof(bl_items),
01570                                                         bl_items, sizeof(bl_info), bl_info)) {
01571                                                  _php_ibase_error(TSRMLS_C);
01572                                                  goto _php_ibase_fetch_error;
01573                                           }
01574 
01575                                           /* find total length of blob's data */
01576                                           for (i = 0; i < sizeof(bl_info); ) {
01577                                                  unsigned short item_len;
01578                                                  char item = bl_info[i++];
01579 
01580                                                  if (item == isc_info_end || item == isc_info_truncated || 
01581                                                         item == isc_info_error || i >= sizeof(bl_info)) {
01582 
01583                                                         _php_ibase_module_error("Could not determine BLOB size (internal error)"
01584                                                                TSRMLS_CC);
01585                                                         goto _php_ibase_fetch_error;
01586                                                  }                                                       
01587 
01588                                                  item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2);
01589 
01590                                                  if (item == isc_info_blob_total_length) {
01591                                                         max_len = isc_vax_integer(&bl_info[i+2], item_len);
01592                                                         break;
01593                                                  }
01594                                                  i += item_len+2;
01595                                           }
01596 
01597                                           if (max_len == 0) {
01598                                                  ZVAL_STRING(result, "", 1);
01599                                           } else if (SUCCESS != _php_ibase_blob_get(result, &blob_handle, 
01600                                                         max_len TSRMLS_CC)) {
01601                                                  goto _php_ibase_fetch_error;
01602                                           }
01603 
01604                                           if (isc_close_blob(IB_STATUS, &blob_handle.bl_handle)) {
01605                                                  _php_ibase_error(TSRMLS_C);
01606                                                  goto _php_ibase_fetch_error;
01607                                           }
01608 
01609                                    } else { /* blob id only */
01610                                           ISC_QUAD bl_qd = *(ISC_QUAD *) var->sqldata;
01611                                           ZVAL_STRINGL(result,_php_ibase_quad_to_string(bl_qd), BLOB_ID_LEN, 0);
01612                                    }
01613                                    break;
01614                             case SQL_ARRAY:
01615                                    if (flag & PHP_IBASE_FETCH_ARRAYS) { /* array can be *huge* so only fetch if asked */
01616                                           ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
01617                                           ibase_array *ib_array = &ib_result->out_array[array_cnt++];
01618                                           void *ar_data = emalloc(ib_array->ar_size);
01619 
01620                                           if (isc_array_get_slice(IB_STATUS, &ib_result->link->handle, 
01621                                                         &ib_result->trans->handle, &ar_qd, &ib_array->ar_desc,
01622                                                         ar_data, &ib_array->ar_size)) {
01623                                                  _php_ibase_error(TSRMLS_C);
01624                                                  efree(ar_data);
01625                                                  goto _php_ibase_fetch_error;
01626                                           }
01627 
01628                                           if (FAILURE == _php_ibase_arr_zval(result, ar_data, ib_array->ar_size, ib_array,
01629                                                         0, flag TSRMLS_CC)) {
01630                                                  efree(ar_data);
01631                                                  goto _php_ibase_fetch_error;
01632                                           }
01633                                           efree(ar_data);
01634 
01635                                    } else { /* blob id only */
01636                                           ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
01637                                           ZVAL_STRINGL(result,_php_ibase_quad_to_string(ar_qd), BLOB_ID_LEN, 0);
01638                                    }
01639                                    break;
01640                             _php_ibase_fetch_error:
01641                                    zval_dtor(result);
01642                                    FREE_ZVAL(result);
01643                                    RETURN_FALSE;
01644                      } /* switch */
01645 
01646                      if (fetch_type & FETCH_ROW) {
01647                             add_index_zval(return_value, i, result);
01648                      } else {
01649                             add_assoc_zval(return_value, alias, result);
01650                      }
01651               } else {
01652                      if (fetch_type & FETCH_ROW) {
01653                             add_index_null(return_value, i);
01654                      } else {
01655                             add_assoc_null(return_value, alias);
01656                      }
01657               }
01658        } /* for field */
01659 }
01660 /* }}} */
01661 
01662 /* {{{ proto array ibase_fetch_row(resource result [, int fetch_flags])
01663    Fetch a row  from the results of a query */
01664 PHP_FUNCTION(ibase_fetch_row)
01665 {
01666        _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ROW);
01667 }
01668 /* }}} */
01669 
01670 /* {{{ proto array ibase_fetch_assoc(resource result [, int fetch_flags])
01671    Fetch a row  from the results of a query */
01672 PHP_FUNCTION(ibase_fetch_assoc)
01673 {
01674        _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY);
01675 }
01676 /* }}} */
01677 
01678 /* {{{ proto object ibase_fetch_object(resource result [, int fetch_flags])
01679    Fetch a object from the results of a query */
01680 PHP_FUNCTION(ibase_fetch_object)
01681 {
01682        _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY);
01683 
01684        if (Z_TYPE_P(return_value) == IS_ARRAY) {
01685               object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
01686        }
01687 }
01688 /* }}} */
01689 
01690 
01691 /* {{{ proto bool ibase_name_result(resource result, string name)
01692    Assign a name to a result for use with ... WHERE CURRENT OF <name> statements */
01693 PHP_FUNCTION(ibase_name_result)
01694 {
01695        zval *result_arg;
01696        char *name_arg;
01697        int name_arg_len;
01698        ibase_result *ib_result;
01699 
01700        RESET_ERRMSG;
01701 
01702        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &result_arg, &name_arg, &name_arg_len) == FAILURE) {
01703               return;
01704        }
01705 
01706        ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
01707 
01708        if (isc_dsql_set_cursor_name(IB_STATUS, &ib_result->stmt, name_arg, 0)) {
01709               _php_ibase_error(TSRMLS_C);
01710               RETURN_FALSE;
01711        }
01712        RETURN_TRUE;
01713 }
01714 /* }}} */
01715 
01716 
01717 /* {{{ proto bool ibase_free_result(resource result)
01718    Free the memory used by a result */
01719 PHP_FUNCTION(ibase_free_result)
01720 {
01721        zval *result_arg;
01722        ibase_result *ib_result;
01723 
01724        RESET_ERRMSG;
01725 
01726        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result_arg) == FAILURE) {
01727               return;
01728        }
01729 
01730        ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
01731        zend_list_delete(Z_RESVAL_P(result_arg));
01732        RETURN_TRUE;
01733 }
01734 /* }}} */
01735 
01736 /* {{{ proto resource ibase_prepare(resource link_identifier[, string query [, resource trans_identifier ]])
01737    Prepare a query for later execution */
01738 PHP_FUNCTION(ibase_prepare)
01739 {
01740        zval *link_arg, *trans_arg;
01741        ibase_db_link *ib_link;
01742        ibase_trans *trans = NULL;
01743        int query_len, trans_res_id = 0;
01744        ibase_query *ib_query;
01745        char *query;
01746 
01747        RESET_ERRMSG;
01748        
01749        if (ZEND_NUM_ARGS() == 1) {
01750               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
01751                      return;
01752               }
01753               ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
01754        } else if (ZEND_NUM_ARGS() == 2) {
01755               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &link_arg, &query, &query_len) == FAILURE) {
01756                      return;
01757               }
01758               _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &link_arg, &ib_link, &trans);
01759 
01760               if (trans != NULL) {
01761                      trans_res_id = Z_RESVAL_P(link_arg);
01762               }
01763        } else {
01764               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrs", &link_arg, &trans_arg, &query, &query_len) == FAILURE) {
01765                      return;
01766               }
01767               ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, -1, LE_LINK, le_link, le_plink);
01768               ZEND_FETCH_RESOURCE(trans, ibase_trans *, &trans_arg, -1, LE_TRANS, le_trans);
01769               trans_res_id = Z_RESVAL_P(trans_arg);
01770        }
01771 
01772        if (FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC)) {
01773               RETURN_FALSE;
01774        }
01775 
01776        ib_query = (ibase_query *) emalloc(sizeof(ibase_query));
01777 
01778        if (FAILURE == _php_ibase_alloc_query(ib_query, ib_link, trans, query, ib_link->dialect, trans_res_id TSRMLS_CC)) {
01779               efree(ib_query);
01780               RETURN_FALSE;
01781        }
01782        ZEND_REGISTER_RESOURCE(return_value, ib_query, le_query);
01783 }
01784 /* }}} */
01785 
01786 /* {{{ proto mixed ibase_execute(resource query [, mixed bind_arg [, mixed bind_arg [, ...]]])
01787    Execute a previously prepared query */
01788 PHP_FUNCTION(ibase_execute)
01789 {
01790        zval *query, ***args = NULL;
01791        ibase_query *ib_query;
01792        ibase_result *result = NULL;
01793        ALLOCA_FLAG(use_heap)
01794 
01795        RESET_ERRMSG;
01796        
01797        RETVAL_FALSE;
01798 
01799        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() ? 1 : 0 TSRMLS_CC, "r", &query)) {
01800               return;
01801        }
01802 
01803        ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &query, -1, LE_QUERY, le_query);
01804 
01805        do {
01806               int bind_n = ZEND_NUM_ARGS() - 1,
01807                      expected_n = ib_query->in_sqlda ? ib_query->in_sqlda->sqld : 0;
01808 
01809               if (bind_n != expected_n) {
01810                      php_error_docref(NULL TSRMLS_CC, (bind_n < expected_n) ? E_WARNING : E_NOTICE,
01811                             "Statement expects %d arguments, %d given", expected_n, bind_n);
01812 
01813                      if (bind_n < expected_n) {
01814                             break;
01815                      }
01816               }
01817 
01818               /* have variables to bind */
01819               args = (zval ***) do_alloca((expected_n + 1) * sizeof(zval **), use_heap);
01820        
01821               if (FAILURE == zend_get_parameters_array_ex((expected_n + 1), args)) {
01822                      break;
01823               }
01824 
01825               /* Have we used this cursor before and it's still open (exec proc has no cursor) ? */
01826               if (ib_query->result_res_id != 0 
01827                             && ib_query->statement_type != isc_info_sql_stmt_exec_procedure) {
01828                      IBDEBUG("Implicitly closing a cursor");
01829 
01830                      if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_close)) {
01831                             _php_ibase_error(TSRMLS_C);
01832                             break;
01833                      }
01834                      /* invalidate previous results returned by this query (not necessary for exec proc) */
01835                      zend_list_delete(ib_query->result_res_id);       
01836               }
01837 
01838               if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, ib_query, 
01839                             &args[1])) {
01840                   break;
01841               }
01842 
01843               /* free the query if trans handle was released */
01844               if (ib_query->trans->handle == NULL) {
01845                      zend_list_delete(Z_LVAL_P(query));
01846               }
01847        
01848               if (result != NULL) {
01849                      result->type = EXECUTE_RESULT;
01850                      if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) {
01851                             result->stmt = NULL;
01852                      }
01853                      ib_query->result_res_id = zend_list_insert(result, le_result);
01854                      RETVAL_RESOURCE(ib_query->result_res_id);
01855               }
01856        } while (0);
01857 
01858        if (args) {
01859               free_alloca(args, use_heap);
01860        }
01861 }
01862 /* }}} */
01863 
01864 /* {{{ proto bool ibase_free_query(resource query)
01865    Free memory used by a query */
01866 PHP_FUNCTION(ibase_free_query)
01867 {
01868        zval *query_arg;
01869        ibase_query *ib_query;
01870 
01871        RESET_ERRMSG;
01872 
01873        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &query_arg) == FAILURE) {
01874               return;
01875        }
01876 
01877        ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &query_arg, -1, LE_QUERY, le_query);
01878        zend_list_delete(Z_RESVAL_P(query_arg));
01879        RETURN_TRUE;
01880 }
01881 /* }}} */
01882 
01883 /* {{{ proto int ibase_num_fields(resource query_result)
01884    Get the number of fields in result */
01885 PHP_FUNCTION(ibase_num_fields)
01886 {
01887        zval *result;
01888        int type;
01889        XSQLDA *sqlda;
01890 
01891        RESET_ERRMSG;
01892 
01893        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
01894               return;
01895        }
01896 
01897        zend_list_find(Z_RESVAL_P(result), &type);
01898 
01899        if (type == le_query) {
01900               ibase_query *ib_query;
01901 
01902               ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result, -1, LE_QUERY, le_query);
01903               sqlda = ib_query->out_sqlda;
01904        } else {
01905               ibase_result *ib_result;
01906 
01907               ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result, -1, LE_RESULT, le_result);
01908               sqlda = ib_result->out_sqlda;
01909        }
01910 
01911        if (sqlda == NULL) {
01912               RETURN_LONG(0);
01913        } else {
01914               RETURN_LONG(sqlda->sqld);
01915        }
01916 }
01917 /* }}} */
01918 
01919 static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */
01920 {
01921        unsigned short len;
01922        char buf[16], *s = buf;
01923 
01924        array_init(return_value);
01925 
01926        add_index_stringl(return_value, 0, var->sqlname, var->sqlname_length, 1);
01927        add_assoc_stringl(return_value, "name", var->sqlname, var->sqlname_length, 1);
01928 
01929        add_index_stringl(return_value, 1, var->aliasname, var->aliasname_length, 1);
01930        add_assoc_stringl(return_value, "alias", var->aliasname, var->aliasname_length, 1);
01931 
01932        add_index_stringl(return_value, 2, var->relname, var->relname_length, 1);
01933        add_assoc_stringl(return_value, "relation", var->relname, var->relname_length, 1);
01934 
01935        len = slprintf(buf, 16, "%d", var->sqllen);
01936        add_index_stringl(return_value, 3, buf, len, 1);
01937        add_assoc_stringl(return_value, "length", buf, len, 1);
01938 
01939        if (var->sqlscale < 0) {
01940               unsigned short precision = 0;
01941 
01942               switch (var->sqltype & ~1) {
01943 
01944                      case SQL_SHORT:
01945                             precision = 4;
01946                             break;
01947                      case SQL_LONG:
01948                             precision = 9;
01949                             break;
01950                      case SQL_INT64:
01951                             precision = 18;
01952                             break;
01953               }
01954               len = slprintf(buf, 16, "NUMERIC(%d,%d)", precision, -var->sqlscale);
01955               add_index_stringl(return_value, 4, s, len, 1);
01956               add_assoc_stringl(return_value, "type", s, len, 1);
01957        } else {
01958               switch (var->sqltype & ~1) {
01959                      case SQL_TEXT:
01960                             s = "CHAR"; 
01961                             break;
01962                      case SQL_VARYING:
01963                             s = "VARCHAR"; 
01964                             break;
01965                      case SQL_SHORT:
01966                             s = "SMALLINT"; 
01967                             break;
01968                      case SQL_LONG:
01969                             s = "INTEGER"; 
01970                             break;
01971                      case SQL_FLOAT:
01972                             s = "FLOAT"; break;
01973                      case SQL_DOUBLE:
01974                      case SQL_D_FLOAT:
01975                             s = "DOUBLE PRECISION"; break;
01976                      case SQL_INT64: 
01977                             s = "BIGINT"; 
01978                             break;
01979                      case SQL_TIMESTAMP:  
01980                             s = "TIMESTAMP"; 
01981                             break;
01982                      case SQL_TYPE_DATE:
01983                             s = "DATE";
01984                             break;
01985                      case SQL_TYPE_TIME:
01986                             s = "TIME"; 
01987                             break;
01988                      case SQL_BLOB:
01989                             s = "BLOB"; 
01990                             break;
01991                      case SQL_ARRAY:
01992                             s = "ARRAY";
01993                             break;
01994                             /* FIXME: provide more detailed information about the field type, field size
01995                              * and array dimensions */
01996                      case SQL_QUAD:
01997                             s = "QUAD";
01998                             break;
01999               }
02000               add_index_string(return_value, 4, s, 1);
02001               add_assoc_string(return_value, "type", s, 1);
02002        }
02003 }
02004 /* }}} */
02005 
02006 /* {{{ proto array ibase_field_info(resource query_result, int field_number)
02007    Get information about a field */
02008 PHP_FUNCTION(ibase_field_info)
02009 {
02010        zval *result_arg;
02011        long field_arg;
02012        int type;
02013        XSQLDA *sqlda;
02014 
02015        RESET_ERRMSG;
02016 
02017        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result_arg, &field_arg) == FAILURE) {
02018               return;
02019        }
02020 
02021        zend_list_find(Z_RESVAL_P(result_arg), &type);
02022 
02023        if (type == le_query) {
02024               ibase_query *ib_query;
02025 
02026               ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result_arg, -1, LE_QUERY, le_query);
02027               sqlda = ib_query->out_sqlda;
02028        } else {
02029               ibase_result *ib_result;
02030 
02031               ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
02032               sqlda = ib_result->out_sqlda;
02033        }                                  
02034 
02035        if (sqlda == NULL) {
02036               _php_ibase_module_error("Trying to get field info from a non-select query" TSRMLS_CC);
02037               RETURN_FALSE;
02038        }
02039 
02040        if (field_arg < 0 || field_arg >= sqlda->sqld) {
02041               RETURN_FALSE;
02042        }
02043        _php_ibase_field_info(return_value, sqlda->sqlvar + field_arg);
02044 }
02045 /* }}} */
02046 
02047 /* {{{ proto int ibase_num_params(resource query)
02048    Get the number of params in a prepared query */
02049 PHP_FUNCTION(ibase_num_params)
02050 {
02051        zval *result;
02052        ibase_query *ib_query;
02053 
02054        RESET_ERRMSG;
02055 
02056        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
02057               return;
02058        }
02059 
02060        ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result, -1, LE_QUERY, le_query);
02061 
02062        if (ib_query->in_sqlda == NULL) {
02063               RETURN_LONG(0);
02064        } else {
02065               RETURN_LONG(ib_query->in_sqlda->sqld);
02066        }
02067 }
02068 /* }}} */
02069 
02070 /* {{{ proto array ibase_param_info(resource query, int field_number)
02071    Get information about a parameter */
02072 PHP_FUNCTION(ibase_param_info)
02073 {
02074        zval *result_arg;
02075        long field_arg;
02076        ibase_query *ib_query;
02077 
02078        RESET_ERRMSG;
02079 
02080        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result_arg, &field_arg) == FAILURE) {
02081               return;
02082        }
02083 
02084        ZEND_FETCH_RESOURCE(ib_query, ibase_query *, &result_arg, -1, LE_QUERY, le_query);
02085 
02086        if (ib_query->in_sqlda == NULL) {
02087               RETURN_FALSE;
02088        }
02089 
02090        if (field_arg < 0 || field_arg >= ib_query->in_sqlda->sqld) {
02091               RETURN_FALSE;
02092        }
02093 
02094        _php_ibase_field_info(return_value,ib_query->in_sqlda->sqlvar + field_arg);
02095 }
02096 /* }}} */
02097 
02098 #endif /* HAVE_IBASE */
02099 
02100 /*
02101  * Local variables:
02102  * tab-width: 4
02103  * c-basic-offset: 4
02104  * End:
02105  * vim600: sw=4 ts=4 fdm=marker
02106  * vim<600: sw=4 ts=4
02107  */