diff --git a/ext/interbase/config.m4 b/ext/interbase/config.m4 index dca634d34de..e61bf49adc7 100644 --- a/ext/interbase/config.m4 +++ b/ext/interbase/config.m4 @@ -53,6 +53,6 @@ if test "$PHP_INTERBASE" != "no"; then PHP_ADD_LIBRARY_WITH_PATH($IBASE_LIBNAME, $IBASE_LIBDIR, INTERBASE_SHARED_LIBADD) PHP_ADD_INCLUDE($IBASE_INCDIR) AC_DEFINE(HAVE_IBASE,1,[ ]) - PHP_NEW_EXTENSION(interbase, interbase.c ibase_service.c ibase_events.c ibase_blobs.c, $ext_shared) + PHP_NEW_EXTENSION(interbase, interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c, $ext_shared) PHP_SUBST(INTERBASE_SHARED_LIBADD) fi diff --git a/ext/interbase/config.w32 b/ext/interbase/config.w32 index 9eab6a4599d..0019861c59a 100644 --- a/ext/interbase/config.w32 +++ b/ext/interbase/config.w32 @@ -9,7 +9,7 @@ if (PHP_INTERBASE != "no" || PHP_INTERBASE5 != "no") { if (CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_INTERBASE", PHP_PHP_BUILD + "\\interbase\\include;" + PHP_INTERBASE) && (CHECK_LIB("fbclient_ms.lib", "interbase", PHP_PHP_BUILD + "\\interbase\\lib_ms;" + PHP_INTERBASE) || CHECK_LIB("gds32_ms.lib", "interbase", PHP_PHP_BUILD + "\\interbase\\lib_ms;" + PHP_INTERBASE))) { - EXTENSION("interbase", "interbase.c ibase_service.c ibase_events.c ibase_blobs.c"); + EXTENSION("interbase", "interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c"); AC_DEFINE('HAVE_IBASE', 1, 'Have interbase library'); if (PHP_INTERBASE != "no") { diff --git a/ext/interbase/ibase_blobs.c b/ext/interbase/ibase_blobs.c index 304d9d7a2de..eae2f74ebb5 100644 --- a/ext/interbase/ibase_blobs.c +++ b/ext/interbase/ibase_blobs.c @@ -32,7 +32,30 @@ #define BLOB_CLOSE 1 #define BLOB_CANCEL 2 -int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */ +static int le_blob; + +static void _php_ibase_free_blob(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_blob *ib_blob = (ibase_blob *)rsrc->ptr; + + if (ib_blob->bl_handle != NULL) { /* blob open*/ + if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) { + _php_ibase_module_error("You can lose data. Close any blob after reading from or " + "writing to it. Use ibase_blob_close() before calling ibase_close()" TSRMLS_CC); + } + } + efree(ib_blob); +} +/* }}} */ + +void php_ibase_blobs_minit(INIT_FUNC_ARGS) /* {{{ */ +{ + le_blob = zend_register_list_destructors_ex(_php_ibase_free_blob, NULL, + "interbase blob", module_number); +} +/* }}} */ + +PHPAPI int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */ { /* shortcut for most common case */ if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) { @@ -49,13 +72,13 @@ int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */ } /* }}} */ -char *_php_ibase_quad_to_string(ISC_QUAD const qd) /* {{{ */ +PHPAPI char *_php_ibase_quad_to_string(ISC_QUAD const qd) /* {{{ */ { char *result = (char *) emalloc(BLOB_ID_LEN+1); /* shortcut for most common case */ if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) { - sprintf(result, BLOB_ID_MASK, *(ISC_UINT64*)(void *) &qd); + sprintf(result, BLOB_ID_MASK, *(ISC_UINT64*)(void *) &qd); } else { ISC_UINT64 res = ((ISC_UINT64) qd.gds_quad_high << 0x20) | qd.gds_quad_low; sprintf(result, BLOB_ID_MASK, res); @@ -73,25 +96,25 @@ typedef struct { /* {{{ */ /* }}} */ } IBASE_BLOBINFO; -int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, unsigned long max_len TSRMLS_DC) /* {{{ */ +PHPAPI int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, unsigned long max_len TSRMLS_DC) /* {{{ */ { if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/ - + ISC_STATUS stat; char *bl_data; unsigned long cur_len; unsigned short seg_len; - + bl_data = emalloc(max_len + 1); - + for (cur_len = stat = 0; (stat == 0 || stat == isc_segment) && cur_len < max_len; cur_len += seg_len) { - - unsigned short chunk_size = (max_len-cur_len) > USHRT_MAX ? USHRT_MAX + + unsigned short chunk_size = (max_len-cur_len) > USHRT_MAX ? USHRT_MAX : (unsigned short)(max_len-cur_len); - - stat = isc_get_segment(IB_STATUS, &ib_blob->bl_handle, &seg_len, chunk_size, &bl_data[cur_len]); + + stat = isc_get_segment(IB_STATUS, &ib_blob->bl_handle, &seg_len, chunk_size, &bl_data[cur_len]); } - + bl_data[cur_len] = '\0'; if (IB_STATUS[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) { efree(bl_data); @@ -106,7 +129,7 @@ int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, unsigned long m } /* }}} */ -int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC) /* {{{ */ +PHPAPI int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC) /* {{{ */ { unsigned long put_cnt = 0, rem_cnt; unsigned short chunk_size; @@ -114,7 +137,7 @@ int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC) /* {{{ convert_to_string_ex(string_arg); for (rem_cnt = Z_STRLEN_PP(string_arg); rem_cnt > 0; rem_cnt -= chunk_size) { - + chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (unsigned short)rem_cnt; if (isc_put_segment(IB_STATUS, &ib_blob->bl_handle, chunk_size, &Z_STRVAL_PP(string_arg)[put_cnt] )) { @@ -124,7 +147,7 @@ int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC) /* {{{ put_cnt += chunk_size; } return SUCCESS; -} +} /* }}} */ static int _php_ibase_blob_info(isc_blob_handle bl_handle, IBASE_BLOBINFO *bl_info TSRMLS_DC) /* {{{ */ @@ -135,7 +158,7 @@ static int _php_ibase_blob_info(isc_blob_handle bl_handle, IBASE_BLOBINFO *bl_in isc_info_blob_total_length, isc_info_blob_type }; - + char bl_inf[sizeof(long)*8], *p; bl_info->max_segment = 0; @@ -190,23 +213,23 @@ PHP_FUNCTION(ibase_blob_create) ibase_blob *ib_blob; RESET_ERRMSG; - + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &link)) { RETURN_FALSE; } PHP_IBASE_LINK_TRANS(link, ib_link, trans); - + ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob)); ib_blob->bl_handle = NULL; ib_blob->type = BLOB_INPUT; - + if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, &ib_blob->bl_qd)) { _php_ibase_error(TSRMLS_C); efree(ib_blob); RETURN_FALSE; } - + ZEND_REGISTER_RESOURCE(return_value, ib_blob, le_blob); } /* }}} */ @@ -226,7 +249,7 @@ PHP_FUNCTION(ibase_blob_open) switch (ZEND_NUM_ARGS()) { default: - WRONG_PARAM_COUNT; + WRONG_PARAM_COUNT; case 1: if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &blob_id, &blob_id_len)) { RETURN_FALSE; @@ -238,13 +261,13 @@ PHP_FUNCTION(ibase_blob_open) } break; } - + PHP_IBASE_LINK_TRANS(link, ib_link, trans); ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob)); ib_blob->bl_handle = NULL; ib_blob->type = BLOB_OUTPUT; - + do { if (! _php_ibase_string_to_quad(blob_id, &ib_blob->bl_qd)) { _php_ibase_module_error("String is not a BLOB ID" TSRMLS_CC); @@ -256,7 +279,7 @@ PHP_FUNCTION(ibase_blob_open) _php_ibase_error(TSRMLS_C); break; } - + ZEND_REGISTER_RESOURCE(return_value, ib_blob, le_blob); return; @@ -327,13 +350,13 @@ static void _php_ibase_blob_end(INTERNAL_FUNCTION_PARAMETERS, int bl_end) /* {{{ ibase_blob *ib_blob; RESET_ERRMSG; - + if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &blob_arg) == FAILURE) { WRONG_PARAM_COUNT; } - ZEND_FETCH_RESOURCE(ib_blob, ibase_blob *, blob_arg, -1, "Interbase blob", le_blob); - + ZEND_FETCH_RESOURCE(ib_blob, ibase_blob *, blob_arg, -1, "Interbase blob", le_blob); + if (bl_end == BLOB_CLOSE) { /* return id here */ if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/ @@ -389,7 +412,7 @@ PHP_FUNCTION(ibase_blob_info) switch (ZEND_NUM_ARGS()) { default: - WRONG_PARAM_COUNT; + WRONG_PARAM_COUNT; case 1: if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &blob_id, &blob_id_len)) { RETURN_FALSE; @@ -431,7 +454,7 @@ PHP_FUNCTION(ibase_blob_info) } array_init(return_value); - + add_index_long(return_value, 0, bl_info.total_length); add_assoc_long(return_value, "length", bl_info.total_length); @@ -457,16 +480,16 @@ PHP_FUNCTION(ibase_blob_echo) int blob_id_len; zval *link = NULL; ibase_db_link *ib_link; - ibase_trans *trans = NULL; + ibase_trans *trans = NULL; ibase_blob ib_blob_id = { NULL, BLOB_OUTPUT }; - char bl_data[IBASE_BLOB_SEG]; + char bl_data[IBASE_BLOB_SEG]; unsigned short seg_len; RESET_ERRMSG; switch (ZEND_NUM_ARGS()) { default: - WRONG_PARAM_COUNT; + WRONG_PARAM_COUNT; case 1: if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &blob_id, &blob_id_len)) { RETURN_FALSE; @@ -491,16 +514,16 @@ PHP_FUNCTION(ibase_blob_echo) &ib_blob_id.bl_qd)) { break; } - + while (!isc_get_segment(IB_STATUS, &ib_blob_id.bl_handle, &seg_len, sizeof(bl_data), bl_data) || IB_STATUS[1] == isc_segment) { PHPWRITE(bl_data, seg_len); } - + if (IB_STATUS[0] && (IB_STATUS[1] != isc_segstr_eof)) { break; } - + if (isc_close_blob(IB_STATUS, &ib_blob_id.bl_handle)) { break; } @@ -527,27 +550,27 @@ PHP_FUNCTION(ibase_blob_import) RESET_ERRMSG; - if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|r", + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|r", (ZEND_NUM_ARGS()-1) ? &link : &file, &file)) { RETURN_FALSE; } - + PHP_IBASE_LINK_TRANS(link, ib_link, trans); php_stream_from_zval(stream, &file); - + do { if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle, &ib_blob.bl_qd)) { break; } - + for (size = 0; (b = php_stream_read(stream, bl_data, sizeof(bl_data))); size += b) { if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) { break; } } - + if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { break; } diff --git a/ext/interbase/ibase_events.c b/ext/interbase/ibase_events.c index a5361964a59..dc8fab36a45 100644 --- a/ext/interbase/ibase_events.c +++ b/ext/interbase/ibase_events.c @@ -29,13 +29,66 @@ #include "php_interbase.h" #include "php_ibase_includes.h" -void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */ +static int le_event; + +static void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */ { isc_free(event_buf); isc_free(result_buf); } /* }}} */ +PHPAPI void _php_ibase_free_event(ibase_event *event TSRMLS_DC) /* {{{ */ +{ + unsigned short i; + + event->state = DEAD; + + if (event->link != NULL) { + ibase_event **node; + + if (event->link->handle != NULL && + isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) { + _php_ibase_error(TSRMLS_C); + } + + /* delete this event from the link struct */ + for (node = &event->link->event_head; *node != event; node = &(*node)->event_next); + *node = event->event_next; + } + + if (event->callback) { + zval_dtor(event->callback); + FREE_ZVAL(event->callback); + event->callback = NULL; + + _php_ibase_event_free(event->event_buffer,event->result_buffer); + + for (i = 0; i < event->event_count; ++i) { + efree(event->events[i]); + } + efree(event->events); + } +} +/* }}} */ + +static void _php_ibase_free_event_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_event *e = (ibase_event *) rsrc->ptr; + + _php_ibase_free_event(e TSRMLS_CC); + + efree(e); +} +/* }}} */ + +void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */ +{ + le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, + "interbase event", module_number); +} +/* }}} */ + static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, /* {{{ */ char **events, unsigned short *l, char **event_buf, char **result_buf) { @@ -43,7 +96,7 @@ static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, unsigned long dummy_count[15]; /** - * Unfortunately, there's no clean and portable way in C to pass arguments to + * Unfortunately, there's no clean and portable way in C to pass arguments to * a variadic function if you don't know the number of arguments at compile time. * (And even if there were a way, the Interbase API doesn't provide a version of * this function that takes a va_list as an argument) @@ -52,8 +105,8 @@ static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, * so we can work around it. */ - *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0], - events[1], events[2], events[3], events[4], events[5], events[6], events[7], + *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0], + events[1], events[2], events[3], events[4], events[5], events[6], events[7], events[8], events[9], events[10], events[11], events[12], events[13], events[14]); /** @@ -78,7 +131,7 @@ PHP_FUNCTION(ibase_wait_event) char *event_buffer, *result_buffer, *events[15]; unsigned short i = 0, event_count = 0, buffer_size; unsigned long occurred_event[15]; - + RESET_ERRMSG; /* no more than 15 events */ @@ -102,8 +155,8 @@ PHP_FUNCTION(ibase_wait_event) } ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink); - } - + } + for (; i < ZEND_NUM_ARGS(); ++i) { convert_to_string_ex(args[i]); events[event_count++] = Z_STRVAL_PP(args[i]); @@ -118,7 +171,7 @@ PHP_FUNCTION(ibase_wait_event) _php_ibase_event_free(event_buffer,result_buffer); RETURN_FALSE; } - + /* find out which event occurred */ isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer); for (i = 0; i < event_count; ++i) { @@ -128,7 +181,7 @@ PHP_FUNCTION(ibase_wait_event) RETURN_STRING(result,0); } } - + /* If we reach this line, isc_wait_for_event() did return, but we don't know which event fired. */ _php_ibase_event_free(event_buffer,result_buffer); @@ -141,10 +194,10 @@ static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ { /* this function is called asynchronously by the Interbase client library. */ TSRMLS_FETCH_FROM_CTX(event->thread_ctx); - + /** * The callback function is called when the event is first registered and when the event - * is cancelled. I consider this is a bug. By clearing event->callback first and setting + * is cancelled. I consider this is a bug. By clearing event->callback first and setting * it to -1 later, we make sure nothing happens if no event was actually posted. */ switch (event->state) { @@ -155,16 +208,16 @@ static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ default: /* == DEAD */ break; case ACTIVE: - args[0] = &event_name; - args[1] = &link_id; - + args[0] = &event_name; + args[1] = &link_id; + /* copy the updated results into the result buffer */ memcpy(event->result_buffer, result_buf, buffer_size); - + INIT_ZVAL(event_name); INIT_ZVAL(link_id); ZVAL_RESOURCE(&link_id, event->link_res_id); - + /* find out which event occurred */ isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer); for (i = 0; i < event->event_count; ++i) { @@ -172,24 +225,24 @@ static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ ZVAL_STRING(&event_name,event->events[i],0); break; } - } - + } + /* call the callback provided by the user */ - if (SUCCESS != call_user_function(EG(function_table), NULL, + if (SUCCESS != call_user_function(EG(function_table), NULL, event->callback, &return_value, 2, args TSRMLS_CC)) { _php_ibase_module_error("Error calling callback %s" TSRMLS_CC, Z_STRVAL_P(event->callback)); break; } - + if (Z_TYPE(return_value) == IS_BOOL && !Z_BVAL(return_value)) { event->state = DEAD; break; - } + } case NEW: /* re-register the event */ - if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size, + if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size, event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) { - + _php_ibase_error(TSRMLS_C); } event->state = ACTIVE; @@ -203,8 +256,8 @@ static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ PHP_FUNCTION(ibase_set_event_handler) { /** - * The callback passed to this function should take an event name (string) and a - * link resource id (int) as arguments. The value returned from the function is + * The callback passed to this function should take an event name (string) and a + * link resource id (int) as arguments. The value returned from the function is * used to determine if the event handler should remain set. */ @@ -213,7 +266,7 @@ PHP_FUNCTION(ibase_set_event_handler) ibase_event *event; unsigned short i = 1, buffer_size; int link_res_id; - + RESET_ERRMSG; /* no more than 15 events */ @@ -231,7 +284,7 @@ PHP_FUNCTION(ibase_set_event_handler) cb_arg = args[1]; i = 2; - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, args[0], -1, + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink); convert_to_long_ex(args[0]); @@ -245,18 +298,18 @@ PHP_FUNCTION(ibase_set_event_handler) cb_arg = args[0]; - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink); link_res_id = IBG(default_link); - } - + } + /* get the callback */ if (!zend_is_callable(*cb_arg, 0, NULL)) { _php_ibase_module_error("Callback argument %s is not a callable function" TSRMLS_CC, Z_STRVAL_PP(cb_arg)); RETURN_FALSE; } - + /* allocate the event resource */ event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0); TSRMLS_SET_CTX(event->thread_ctx); @@ -270,28 +323,28 @@ PHP_FUNCTION(ibase_set_event_handler) *event->callback = **cb_arg; INIT_PZVAL(event->callback); zval_copy_ctor(event->callback); - + for (; i < ZEND_NUM_ARGS(); ++i) { convert_to_string_ex(args[i]); event->events[event->event_count++] = estrdup(Z_STRVAL_PP(args[i])); } /* fills the required data structure with information about the events */ - _php_ibase_event_block(ib_link, event->event_count, event->events, + _php_ibase_event_block(ib_link, event->event_count, event->events, &buffer_size, &event->event_buffer, &event->result_buffer); - + /* now register the events with the Interbase API */ - if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size, + if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size, event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) { - + _php_ibase_error(TSRMLS_C); efree(event); RETURN_FALSE; } - + event->event_next = ib_link->event_head; ib_link->event_head = event; - + ZEND_REGISTER_RESOURCE(return_value, event, le_event); zend_list_addref(Z_LVAL_P(return_value)); } @@ -302,14 +355,14 @@ PHP_FUNCTION(ibase_set_event_handler) PHP_FUNCTION(ibase_free_event_handler) { zval *event_arg; - + RESET_ERRMSG; - + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &event_arg)) { ibase_event *event; ZEND_FETCH_RESOURCE(event, ibase_event *, &event_arg, -1, "Interbase event", le_event); - + event->state = DEAD; zend_list_delete(Z_LVAL_P(event_arg)); @@ -317,7 +370,7 @@ PHP_FUNCTION(ibase_free_event_handler) } else { RETURN_FALSE; } -} +} /* }}} */ #endif /* HAVE_IBASE */ diff --git a/ext/interbase/ibase_query.c b/ext/interbase/ibase_query.c new file mode 100644 index 00000000000..a29a64c3284 --- /dev/null +++ b/ext/interbase/ibase_query.c @@ -0,0 +1,2131 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Ard Biesheuvel | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" + +#if HAVE_IBASE + +#include "ext/standard/php_standard.h" +#include "php_interbase.h" +#include "php_ibase_includes.h" + +#define ISC_LONG_MIN INT_MIN +#define ISC_LONG_MAX INT_MAX + +#define QUERY_RESULT 1 +#define EXECUTE_RESULT 2 + +#define FETCH_ROW 1 +#define FETCH_ARRAY 2 + +typedef struct { + unsigned short vary_length; + char vary_string[1]; +} IBVARY; + +/* sql variables union + * used for convert and binding input variables + */ +typedef struct { + union { + short sval; + float fval; + ISC_LONG lval; + ISC_QUAD qval; +#ifdef SQL_TIMESTAMP + ISC_TIMESTAMP tsval; + ISC_DATE dtval; + ISC_TIME tmval; +#endif + } val; + short sqlind; +} BIND_BUF; + +static int le_result, le_query; + +static void _php_ibase_free_xsqlda(XSQLDA *sqlda) /* {{{ */ +{ + int i; + XSQLVAR *var; + + IBDEBUG("Free XSQLDA?"); + if (sqlda) { + IBDEBUG("Freeing XSQLDA..."); + var = sqlda->sqlvar; + for (i = 0; i < sqlda->sqld; i++, var++) { + efree(var->sqldata); + if (var->sqlind) { + efree(var->sqlind); + } + } + efree(sqlda); + } +} +/* }}} */ + +static void _php_ibase_free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_result *ib_result = (ibase_result *) rsrc->ptr; + + IBDEBUG("Freeing result by dtor..."); + if (ib_result) { + _php_ibase_free_xsqlda(ib_result->out_sqlda); + if (ib_result->stmt && ib_result->type != EXECUTE_RESULT) { + IBDEBUG("Dropping statement handle (free_result dtor)..."); + isc_dsql_free_statement(IB_STATUS, &ib_result->stmt, DSQL_drop); + } + efree(ib_result); + } +} +/* }}} */ + +static void _php_ibase_free_query(ibase_query *ib_query TSRMLS_DC) /* {{{ */ +{ + IBDEBUG("Freeing query..."); + + if (ib_query->in_sqlda) { + efree(ib_query->in_sqlda); + } + if (ib_query->out_sqlda) { + efree(ib_query->out_sqlda); + } + if (ib_query->stmt) { + IBDEBUG("Dropping statement handle (free_query)..."); + if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_drop)) { + _php_ibase_error(TSRMLS_C); + } + } + if (ib_query->in_array) { + efree(ib_query->in_array); + } + if (ib_query->out_array) { + efree(ib_query->out_array); + } + if (ib_query->query) { + efree(ib_query->query); + } +} +/* }}} */ + +static void php_ibase_free_query_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_query *ib_query = (ibase_query *)rsrc->ptr; + + if (ib_query != NULL) { + IBDEBUG("Preparing to free query by dtor..."); + + _php_ibase_free_query(ib_query TSRMLS_CC); + if (ib_query->statement_type != isc_info_sql_stmt_exec_procedure) { + zend_list_delete(ib_query->result_res_id); + } + efree(ib_query); + } +} +/* }}} */ + +void php_ibase_query_minit(INIT_FUNC_ARGS) /* {{{ */ +{ + le_result = zend_register_list_destructors_ex(_php_ibase_free_result, NULL, + "interbase result", module_number); + le_query = zend_register_list_destructors_ex(php_ibase_free_query_rsrc, NULL, + "interbase query", module_number); +} +/* }}} */ + +static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ */ + isc_db_handle link, isc_tr_handle trans, unsigned short *array_cnt TSRMLS_DC) +{ + unsigned short i, n; + ibase_array *ar; + + /* first check if we have any arrays at all */ + for (i = *array_cnt = 0; i < sqlda->sqld; ++i) { + if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_ARRAY) { + ++*array_cnt; + } + } + if (! *array_cnt) return SUCCESS; + + ar = safe_emalloc(sizeof(ibase_array), *array_cnt, 0); + + for (i = n = 0; i < sqlda->sqld; ++i) { + unsigned short dim; + unsigned long ar_size = 1; + XSQLVAR *var = &sqlda->sqlvar[i]; + + if ((var->sqltype & ~1) == SQL_ARRAY) { + ibase_array *a = &ar[n++]; + ISC_ARRAY_DESC *ar_desc = &a->ar_desc; + + if (isc_array_lookup_bounds(IB_STATUS, &link, &trans, var->relname, + var->sqlname, ar_desc)) { + _php_ibase_error(TSRMLS_C); + efree(ar); + return FAILURE; + } + + switch (ar_desc->array_desc_dtype) { + case blr_text: + case blr_text2: + a->el_type = SQL_TEXT; + a->el_size = ar_desc->array_desc_length; + break; + case blr_short: + a->el_type = SQL_SHORT; + a->el_size = sizeof(short); + break; + case blr_long: + a->el_type = SQL_LONG; + a->el_size = sizeof(ISC_LONG); + break; + case blr_float: + a->el_type = SQL_FLOAT; + a->el_size = sizeof(float); + break; + case blr_double: + a->el_type = SQL_DOUBLE; + a->el_size = sizeof(double); + break; +#ifdef blr_int64 + case blr_int64: + a->el_type = SQL_INT64; + a->el_size = sizeof(ISC_INT64); + break; +#endif +#ifndef blr_timestamp + case blr_date: + a->el_type = SQL_DATE; + a->el_size = sizeof(ISC_QUAD); + break; +#else + case blr_timestamp: + a->el_type = SQL_TIMESTAMP; + a->el_size = sizeof(ISC_TIMESTAMP); + break; + case blr_sql_date: + a->el_type = SQL_TYPE_DATE; + a->el_size = sizeof(ISC_DATE); + break; + case blr_sql_time: + a->el_type = SQL_TYPE_TIME; + a->el_size = sizeof(ISC_TIME); + break; +#endif + case blr_varying: + case blr_varying2: + /** + * IB has a strange way of handling VARCHAR arrays. It doesn't store + * the length in the first short, as with VARCHAR fields. It does, + * however, expect the extra short to be allocated for each element. + */ + a->el_type = SQL_TEXT; + a->el_size = ar_desc->array_desc_length + sizeof(short); + break; + case blr_quad: + case blr_blob_id: + case blr_cstring: + case blr_cstring2: + /** + * These types are mentioned as array types in the manual, but I + * wouldn't know how to create an array field with any of these + * types. I assume these types are not applicable to arrays, and + * were mentioned erroneously. + */ + default: + _php_ibase_module_error("Unsupported array type %d in relation '%s' column '%s'" + TSRMLS_CC, ar_desc->array_desc_dtype, var->relname, var->sqlname); + efree(ar); + return FAILURE; + } /* switch array_desc_type */ + + /* calculate elements count */ + for (dim = 0; dim < ar_desc->array_desc_dimensions; dim++) { + ar_size *= 1 + ar_desc->array_desc_bounds[dim].array_bound_upper + -ar_desc->array_desc_bounds[dim].array_bound_lower; + } + a->ar_size = a->el_size * ar_size; + } /* if SQL_ARRAY */ + } /* for column */ + *ib_arrayp = ar; + return SUCCESS; +} +/* }}} */ + +/* allocate and prepare query */ +static int _php_ibase_alloc_query(ibase_query *ib_query, ibase_db_link *link, /* {{{ */ + ibase_trans *trans, char *query, unsigned short dialect, int trans_res_id TSRMLS_DC) +{ + static char info_type[] = {isc_info_sql_stmt_type}; + char result[8]; + + ib_query->link = link; + ib_query->trans = trans; + ib_query->result_res_id = 0; + ib_query->stmt = NULL; + ib_query->in_array = NULL; + ib_query->out_array = NULL; + ib_query->dialect = dialect; + ib_query->query = estrdup(query); + ib_query->trans_res_id = trans_res_id; + + if (isc_dsql_allocate_statement(IB_STATUS, &link->handle, &ib_query->stmt)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_alloc_query_error; + } + + ib_query->out_sqlda = (XSQLDA *) emalloc(XSQLDA_LENGTH(1)); + ib_query->out_sqlda->sqln = 1; + ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION; + + if (isc_dsql_prepare(IB_STATUS, &ib_query->trans->handle, &ib_query->stmt, + 0, query, dialect, ib_query->out_sqlda)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_alloc_query_error; + } + + /* find out what kind of statement was prepared */ + if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_type), + info_type, sizeof(result), result)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_alloc_query_error; + } + ib_query->statement_type = result[3]; + + /* not enough output variables ? */ + if (ib_query->out_sqlda->sqld > ib_query->out_sqlda->sqln) { + ib_query->out_sqlda = erealloc(ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld)); + ib_query->out_sqlda->sqln = ib_query->out_sqlda->sqld; + ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION; + if (isc_dsql_describe(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->out_sqlda)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_alloc_query_error; + } + } + + /* maybe have input placeholders? */ + ib_query->in_sqlda = emalloc(XSQLDA_LENGTH(1)); + ib_query->in_sqlda->sqln = 1; + ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION; + if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_alloc_query_error; + } + + /* not enough input variables ? */ + if (ib_query->in_sqlda->sqln < ib_query->in_sqlda->sqld) { + ib_query->in_sqlda = erealloc(ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld)); + ib_query->in_sqlda->sqln = ib_query->in_sqlda->sqld; + ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION; + + if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, + SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_alloc_query_error; + } + } + + /* no, haven't placeholders at all */ + if (ib_query->in_sqlda->sqld == 0) { + efree(ib_query->in_sqlda); + ib_query->in_sqlda = NULL; + } else if (FAILURE == _php_ibase_alloc_array(&ib_query->in_array, ib_query->in_sqlda, + link->handle, trans->handle, &ib_query->in_array_cnt TSRMLS_CC)) { + goto _php_ibase_alloc_query_error; + } + + if (ib_query->out_sqlda->sqld == 0) { + efree(ib_query->out_sqlda); + ib_query->out_sqlda = NULL; + } else if (FAILURE == _php_ibase_alloc_array(&ib_query->out_array, ib_query->out_sqlda, + link->handle, trans->handle, &ib_query->out_array_cnt TSRMLS_CC)) { + goto _php_ibase_alloc_query_error; + } + + return SUCCESS; + +_php_ibase_alloc_query_error: + + if (ib_query->out_sqlda) { + efree(ib_query->out_sqlda); + } + if (ib_query->in_sqlda) { + efree(ib_query->in_sqlda); + } + if (ib_query->out_array) { + efree(ib_query->out_array); + } + if (ib_query->query) { + efree(ib_query->query); + } + return FAILURE; +} +/* }}} */ + +static int _php_ibase_bind_array(zval *val, char *buf, unsigned long buf_size, /* {{{ */ + ibase_array *array, int dim TSRMLS_DC) +{ + zval null_val, *pnull_val = &null_val; + int u_bound = array->ar_desc.array_desc_bounds[dim].array_bound_upper, + l_bound = array->ar_desc.array_desc_bounds[dim].array_bound_lower, + dim_len = 1 + u_bound - l_bound; + + ZVAL_NULL(pnull_val); + + if (dim < array->ar_desc.array_desc_dimensions) { + unsigned long slice_size = buf_size / dim_len; + unsigned short i; + zval **subval = &val; + + if (Z_TYPE_P(val) == IS_ARRAY) { + zend_hash_internal_pointer_reset(Z_ARRVAL_P(val)); + } + + for (i = 0; i < dim_len; ++i) { + + if (Z_TYPE_P(val) == IS_ARRAY && + zend_hash_get_current_data(Z_ARRVAL_P(val), (void *) &subval) == FAILURE) + { + subval = &pnull_val; + } + + if (_php_ibase_bind_array(*subval, buf, slice_size, array, dim+1 TSRMLS_CC) == FAILURE) + { + return FAILURE; + } + buf += slice_size; + + if (Z_TYPE_P(val) == IS_ARRAY) { + zend_hash_move_forward(Z_ARRVAL_P(val)); + } + } + + if (Z_TYPE_P(val) == IS_ARRAY) { + zend_hash_internal_pointer_reset(Z_ARRVAL_P(val)); + } + + } else { + /* expect a single value */ + if (Z_TYPE_P(val) == IS_NULL) { + memset(buf, 0, buf_size); + } else if (array->ar_desc.array_desc_scale < 0) { + + /* no coercion for array types */ + double l; + + convert_to_double(val); + + if (Z_DVAL_P(val) > 0) { + l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) + .5; + } else { + l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) - .5; + } + + switch (array->el_type) { + case SQL_SHORT: + if (l > SHRT_MAX || l < SHRT_MIN) { + _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); + return FAILURE; + } + *(short*) buf = (short) l; + break; + case SQL_LONG: + if (l > ISC_LONG_MAX || l < ISC_LONG_MIN) { + _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); + return FAILURE; + } + *(ISC_LONG*) buf = (ISC_LONG) l; + break; +#ifdef SQL_INT64 + case SQL_INT64: + { + long double l; + + convert_to_string(val); + + if (!sscanf(Z_STRVAL_P(val), "%Lf", &l)) { + _php_ibase_module_error("Cannot convert '%s' to long double" + TSRMLS_CC, Z_STRVAL_P(val)); + return FAILURE; + } + + if (l > 0) { + *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10, + -array->ar_desc.array_desc_scale) + .5); + } else { + *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10, + -array->ar_desc.array_desc_scale) - .5); + } + } + break; +#endif + } + } else { + struct tm t = { 0, 0, 0, 0, 0, 0 }; + + switch (array->el_type) { + unsigned short n; + + case SQL_SHORT: + convert_to_long(val); + if (Z_LVAL_P(val) > SHRT_MAX || Z_LVAL_P(val) < SHRT_MIN) { + _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); + return FAILURE; + } + *(short *) buf = (short) Z_LVAL_P(val); + break; + case SQL_LONG: + convert_to_long(val); +#if (SIZEOF_LONG > 4) + if (Z_LVAL_P(val) > ISC_LONG_MAX || Z_LVAL_P(val) < ISC_LONG_MIN) { + _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); + return FAILURE; + } +#endif + *(ISC_LONG *) buf = (ISC_LONG) Z_LVAL_P(val); + break; +#ifdef SQL_INT64 + case SQL_INT64: +#if (SIZEOF_LONG >= 8) + convert_to_long(val); + *(long *) buf = Z_LVAL_P(val); +#else + { + ISC_INT64 l; + + convert_to_string(val); + if (!sscanf(Z_STRVAL_P(val), "%" LL_MASK "d", &l)) { + _php_ibase_module_error("Cannot convert '%s' to long integer" + TSRMLS_CC, Z_STRVAL_P(val)); + return FAILURE; + } else { + *(ISC_INT64 *) buf = l; + } + } +#endif + break; +#endif + case SQL_FLOAT: + convert_to_double(val); + *(float*) buf = (float) Z_DVAL_P(val); + break; + case SQL_DOUBLE: + convert_to_double(val); + *(double*) buf = Z_DVAL_P(val); + break; +#ifndef SQL_TIMESTAMP + case SQL_DATE: +#else + case SQL_TIMESTAMP: +#endif + convert_to_string(val); +#ifdef HAVE_STRPTIME + strptime(Z_STRVAL_P(val), IBG(timestampformat), &t); +#else + n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d", + &t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec); + + if (n != 3 && n != 6) { + _php_ibase_module_error("Invalid date/time format (expected 3 or 6 fields, got %d." + " Use format 'm/d/Y H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val)); + return FAILURE; + } + t.tm_year -= 1900; + t.tm_mon--; +#endif +#ifndef SQL_TIMESTAMP + isc_encode_date(&t, (ISC_QUAD *) buf); + break; +#else + isc_encode_timestamp(&t, (ISC_TIMESTAMP * ) buf); + break; + case SQL_TYPE_DATE: + convert_to_string(val); +#ifdef HAVE_STRPTIME + strptime(Z_STRVAL_P(val), IBG(dateformat), &t); +#else + n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d", &t.tm_mon, &t.tm_mday, &t.tm_year); + + if (n != 3) { + _php_ibase_module_error("Invalid date format (expected 3 fields, got %d. " + "Use format 'm/d/Y' You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val)); + return FAILURE; + } + t.tm_year -= 1900; + t.tm_mon--; +#endif + isc_encode_sql_date(&t, (ISC_DATE *) buf); + break; + case SQL_TYPE_TIME: + convert_to_string(val); +#ifdef HAVE_STRPTIME + strptime(Z_STRVAL_P(val), IBG(timeformat), &t); +#else + n = sscanf(Z_STRVAL_P(val), "%d%*[:]%d%*[:]%d", &t.tm_hour, &t.tm_min, &t.tm_sec); + + if (n != 3) { + _php_ibase_module_error("Invalid time format (expected 3 fields, got %d. " + "Use format 'H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val)); + return FAILURE; + } +#endif + isc_encode_sql_time(&t, (ISC_TIME *) buf); + break; +#endif + default: + convert_to_string(val); + strncpy(buf, Z_STRVAL_P(val), array->el_size); + buf[array->el_size-1] = '\0'; + } + } + } + return SUCCESS; +} +/* }}} */ + +static int _php_ibase_bind(XSQLDA *sqlda, zval **b_vars, BIND_BUF *buf, /* {{{ */ + ibase_query *ib_query TSRMLS_DC) +{ + int i, array_cnt = 0, rv = SUCCESS; + + for (i = 0; i < sqlda->sqld; ++i) { /* bound vars */ + + zval *b_var = b_vars[i]; + XSQLVAR *var = &sqlda->sqlvar[i]; + + var->sqlind = &buf[i].sqlind; + + if (Z_TYPE_P(b_var) == IS_NULL) { + if ((var->sqltype & 1) != 1) { + _php_ibase_module_error("Parameter %d must have a value" TSRMLS_CC, i+1); + rv = FAILURE; + } + buf[i].sqlind = -1; + if ((var->sqltype & ~1) == SQL_ARRAY) ++array_cnt; + } else { + buf[i].sqlind = 0; + + if (var->sqlscale < 0) { + /* + DECIMAL or NUMERIC field are stored internally as scaled integers. + Coerce it to string and let InterBase's internal routines handle it. + */ + var->sqltype = SQL_TEXT; + } + + var->sqldata = (void*)&buf[i]; + + switch (var->sqltype & ~1) { + struct tm t; + + case SQL_SHORT: + convert_to_long(b_var); + if (Z_LVAL_P(b_var) > SHRT_MAX || Z_LVAL_P(b_var) < SHRT_MIN) { + _php_ibase_module_error("Parameter %d exceeds field width" TSRMLS_CC, i+1); + rv = FAILURE; + break; + } + buf[i].val.sval = (short) Z_LVAL_P(b_var); + break; + case SQL_LONG: + convert_to_long(b_var); +#if (SIZEOF_LONG > 4) + /* ISC_LONG is always 32-bit */ + if (Z_LVAL_P(b_var) > ISC_LONG_MAX || Z_LVAL_P(b_var) < ISC_LONG_MIN) { + _php_ibase_module_error("Parameter %d exceeds field width" TSRMLS_CC, i+1); + rv = FAILURE; + break; + } +#endif + buf[i].val.lval = (ISC_LONG) Z_LVAL_P(b_var); + break; +#if defined(SQL_INT64) && (SIZEOF_LONG == 8) + case SQL_INT64: + convert_to_long(b_var); + var->sqldata = (void *) &Z_LVAL_P(b_var); + break; +#endif + case SQL_FLOAT: + convert_to_double(b_var); + buf[i].val.fval = (float) Z_DVAL_P(b_var); + break; + case SQL_DOUBLE: + convert_to_double(b_var); + var->sqldata = (void *) &Z_DVAL_P(b_var); + break; + + case SQL_DATE: /* == SQL_TIMESTAMP: */ +#ifdef SQL_TIMESTAMP + case SQL_TYPE_DATE: + case SQL_TYPE_TIME: +#endif + if (Z_TYPE_P(b_var) == IS_LONG) { + /* insert timestamp directly */ + t = *gmtime(&Z_LVAL_P(b_var)); + } else { +#ifndef HAVE_STRPTIME +#ifndef SQL_TIMESTAMP + int n; + + t.tm_year = t.tm_mon = t.tm_mday = t.tm_hour = t.tm_min = t.tm_sec = 0; + + n = sscanf(Z_STRVAL_P(b_var), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d", + &t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec); + + if (n != 3 && n != 6) { + _php_ibase_module_error("Parameter %d: invalid date/time format " + "(expected 3 or 6 fields, got %d. Use format m/d/Y H:i:s. You gave '%s')" + TSRMLS_CC, i+1, n, Z_STRVAL_P(b_var)); + rv = FAILURE; + break; + } + t.tm_year -= 1900; + t.tm_mon--; +#else + goto php_ibase_bind_default; /* let IB string handling take over */ +#endif +#else + convert_to_string(b_var); + + switch (var->sqltype & ~1) { + default: /* == case SQL_TIMESTAMP/SQL_DATE: */ + strptime(Z_STRVAL_P(b_var), IBG(timestampformat), &t); + break; + case SQL_TYPE_DATE: + strptime(Z_STRVAL_P(b_var), IBG(dateformat), &t); + break; + case SQL_TYPE_TIME: + strptime(Z_STRVAL_P(b_var), IBG(timeformat), &t); + break; + } +#endif + } + +#ifndef SQL_TIMESTAMP + isc_encode_date(&t, &buf[i].val.qval); +#else + switch (var->sqltype & ~1) { + default: /* == case SQL_TIMESTAMP */ + isc_encode_timestamp(&t, &buf[i].val.tsval); + break; + case SQL_TYPE_DATE: + isc_encode_sql_date(&t, &buf[i].val.dtval); + break; + case SQL_TYPE_TIME: + isc_encode_sql_time(&t, &buf[i].val.tmval); + break; +#endif + } + break; + case SQL_BLOB: + + convert_to_string(b_var); + + if (Z_STRLEN_P(b_var) != BLOB_ID_LEN || + !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) { + + ibase_blob ib_blob = { NULL, BLOB_INPUT }; + + if (isc_create_blob(IB_STATUS, &ib_query->link->handle, + &ib_query->trans->handle, &ib_blob.bl_handle, &ib_blob.bl_qd)) { + _php_ibase_error(TSRMLS_C); + return FAILURE; + } + + if (_php_ibase_blob_add(&b_var, &ib_blob TSRMLS_CC) != SUCCESS) { + return FAILURE; + } + + if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { + _php_ibase_error(TSRMLS_C); + return FAILURE; + } + buf[i].val.qval = ib_blob.bl_qd; + } + break; + case SQL_ARRAY: + if (Z_TYPE_P(b_var) != IS_ARRAY) { + convert_to_string(b_var); + + if (Z_STRLEN_P(b_var) != BLOB_ID_LEN || + !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) { + + _php_ibase_module_error("Parameter %d: invalid array ID" TSRMLS_CC,i+1); + rv = FAILURE; + } + } else { + /* convert the array data into something IB can understand */ + ibase_array *ar = &ib_query->in_array[array_cnt++]; + void *array_data = emalloc(ar->ar_size); + ISC_QUAD array_id = { 0, 0 }; + + if (FAILURE == _php_ibase_bind_array(b_var, array_data, ar->ar_size, + ar, 0 TSRMLS_CC)) { + _php_ibase_module_error("Parameter %d: failed to bind array argument" + TSRMLS_CC,i+1); + efree(array_data); + rv = FAILURE; + break; + } + + if (isc_array_put_slice(IB_STATUS, &ib_query->link->handle, &ib_query->trans->handle, + &array_id, &ar->ar_desc, array_data, &ar->ar_size)) { + _php_ibase_error(TSRMLS_C); + efree(array_data); + return FAILURE; + } + buf[i].val.qval = array_id; + efree(array_data); + } + break; + default: +php_ibase_bind_default: + convert_to_string(b_var); + var->sqldata = Z_STRVAL_P(b_var); + var->sqllen = Z_STRLEN_P(b_var); + var->sqltype = SQL_TEXT; + } /* switch */ + } /* if */ + } /* for */ + return rv; +} +/* }}} */ + +static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */ +{ + int i; + + for (i = 0; i < sqlda->sqld; i++) { + XSQLVAR *var = &sqlda->sqlvar[i]; + + switch (var->sqltype & ~1) { + case SQL_TEXT: + var->sqldata = safe_emalloc(sizeof(char), var->sqllen, 0); + break; + case SQL_VARYING: + var->sqldata = safe_emalloc(sizeof(char), var->sqllen + sizeof(short), 0); + break; + case SQL_SHORT: + var->sqldata = emalloc(sizeof(short)); + break; + case SQL_LONG: + var->sqldata = emalloc(sizeof(ISC_LONG)); + break; + case SQL_FLOAT: + var->sqldata = emalloc(sizeof(float)); + break; + case SQL_DOUBLE: + var->sqldata = emalloc(sizeof(double)); + break; +#ifdef SQL_INT64 + case SQL_INT64: + var->sqldata = emalloc(sizeof(ISC_INT64)); + break; +#endif +#ifdef SQL_TIMESTAMP + case SQL_TIMESTAMP: + var->sqldata = emalloc(sizeof(ISC_TIMESTAMP)); + break; + case SQL_TYPE_DATE: + var->sqldata = emalloc(sizeof(ISC_DATE)); + break; + case SQL_TYPE_TIME: + var->sqldata = emalloc(sizeof(ISC_TIME)); + break; +#else + case SQL_DATE: +#endif + case SQL_BLOB: + case SQL_ARRAY: + var->sqldata = emalloc(sizeof(ISC_QUAD)); + break; + } /* switch */ + + if (var->sqltype & 1) { /* sql NULL flag */ + var->sqlind = emalloc(sizeof(short)); + } else { + var->sqlind = NULL; + } + } /* for */ +} +/* }}} */ + +static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resultp, /* {{{ */ + ibase_query *ib_query, int argc, zval **args) +{ + XSQLDA *in_sqlda = NULL, *out_sqlda = NULL; + BIND_BUF *bind_buf = NULL; + int rv = FAILURE; + static char info_count[] = { isc_info_sql_records }; + char result[64]; + ISC_STATUS isc_result; + + RESET_ERRMSG; + + if (argc > 0 && args != NULL) { + SEPARATE_ZVAL(args); + } + + switch (ib_query->statement_type) { + isc_tr_handle tr; + ibase_tr_list **l; + ibase_trans *trans; + + case isc_info_sql_stmt_start_trans: + + /* a SET TRANSACTION statement should be executed with a NULL trans handle */ + tr = NULL; + + if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, &tr, 0, + ib_query->query, ib_query->dialect, NULL)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_exec_error; + } + + trans = (ibase_trans *) emalloc(sizeof(ibase_trans)); + trans->handle = tr; + trans->link_cnt = 1; + trans->affected_rows = 0; + trans->db_link[0] = ib_query->link; + + if (ib_query->link->tr_list == NULL) { + ib_query->link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); + ib_query->link->tr_list->trans = NULL; + ib_query->link->tr_list->next = NULL; + } + + /* link the transaction into the connection-transaction list */ + for (l = &ib_query->link->tr_list; *l != NULL; l = &(*l)->next); + *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); + (*l)->trans = trans; + (*l)->next = NULL; + + ZEND_REGISTER_RESOURCE(return_value, trans, le_trans); + + return SUCCESS; + + case isc_info_sql_stmt_commit: + case isc_info_sql_stmt_rollback: + + if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, + &ib_query->trans->handle, 0, ib_query->query, ib_query->dialect, NULL)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_exec_error; + } + + if (ib_query->trans->handle == NULL && ib_query->trans_res_id != 0) { + /* transaction was released by the query and was a registered resource, + so we have to release it */ + zend_list_delete(ib_query->trans_res_id); + } + return SUCCESS; + + default: + RETVAL_TRUE; + } + + /* allocate sqlda and output buffers */ + if (ib_query->out_sqlda) { /* output variables in select, select for update */ + ibase_result *res; + + IBDEBUG("Query wants XSQLDA for output"); + res = emalloc(sizeof(ibase_result)+sizeof(ibase_array)*max(0,ib_query->out_array_cnt-1)); + res->link = ib_query->link; + res->trans = ib_query->trans; + res->stmt = ib_query->stmt; + res->statement_type = ib_query->statement_type; + res->has_more_rows = 1; + + out_sqlda = res->out_sqlda = emalloc(XSQLDA_LENGTH(ib_query->out_sqlda->sqld)); + memcpy(out_sqlda, ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld)); + _php_ibase_alloc_xsqlda(out_sqlda); + + if (ib_query->out_array) { + memcpy(&res->out_array, ib_query->out_array, sizeof(ibase_array)*ib_query->out_array_cnt); + } + *ib_resultp = res; + } + + if (ib_query->in_sqlda) { /* has placeholders */ + IBDEBUG("Query wants XSQLDA for input"); + if (ib_query->in_sqlda->sqld != argc) { + _php_ibase_module_error("Placeholders (%d) and variables (%d) mismatch" + TSRMLS_CC, ib_query->in_sqlda->sqld, argc); + goto _php_ibase_exec_error; + } + in_sqlda = emalloc(XSQLDA_LENGTH(ib_query->in_sqlda->sqld)); + memcpy(in_sqlda, ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld)); + bind_buf = safe_emalloc(sizeof(BIND_BUF), ib_query->in_sqlda->sqld, 0); + if (_php_ibase_bind(in_sqlda, args, bind_buf, ib_query TSRMLS_CC) == FAILURE) { + IBDEBUG("Could not bind input XSQLDA"); + goto _php_ibase_exec_error; + } + } + + if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) { + isc_result = isc_dsql_execute2(IB_STATUS, &ib_query->trans->handle, + &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda, out_sqlda); + } else { + isc_result = isc_dsql_execute(IB_STATUS, &ib_query->trans->handle, + &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda); + } + if (isc_result) { + IBDEBUG("Could not execute query"); + _php_ibase_error(TSRMLS_C); + goto _php_ibase_exec_error; + } + ib_query->trans->affected_rows = 0; + + switch (ib_query->statement_type) { + + unsigned long affected_rows; + + case isc_info_sql_stmt_insert: + case isc_info_sql_stmt_update: + case isc_info_sql_stmt_delete: + case isc_info_sql_stmt_exec_procedure: + + if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_count), + info_count, sizeof(result), result)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_exec_error; + } + + affected_rows = 0; + + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1],2); + + while (result[i] != isc_info_end && i < result_size) { + short len = (short)isc_vax_integer(&result[i+1],2); + if (result[i] != isc_info_req_select_count) { + affected_rows += isc_vax_integer(&result[i+3],len); + } + i += len+3; + } + } + if (affected_rows > 0) { + ib_query->trans->affected_rows = affected_rows; + RETVAL_LONG(affected_rows); + } + } + + rv = SUCCESS; + +_php_ibase_exec_error: + + if (in_sqlda) { + efree(in_sqlda); + } + if (bind_buf) + efree(bind_buf); + + if (rv == FAILURE) { + if (*ib_resultp) { + efree(*ib_resultp); + *ib_resultp = NULL; + } + if (out_sqlda) { + _php_ibase_free_xsqlda(out_sqlda); + } + } + + return rv; +} +/* }}} */ + +/* {{{ proto mixed ibase_query([resource link_identifier, [ resource link_identifier, ]] string query [, mixed bind_arg [, mixed bind_arg [, ...]]]) + Execute a query */ +PHP_FUNCTION(ibase_query) +{ + zval ***args, **bind_args = NULL; + int i, bind_n = 0, trans_res_id = 0; + ibase_db_link *ib_link = NULL; + ibase_trans *trans = NULL; + ibase_query ib_query = { NULL, NULL, 0, 0 }; + ibase_result *result = NULL; + char *query; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() < 1) { + WRONG_PARAM_COUNT; + } + + /* use stack to avoid leaks */ + args = (zval ***) do_alloca(sizeof(zval **) * ZEND_NUM_ARGS()); + + RETVAL_FALSE; + + if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + goto ibase_query_end; + + } + + i = 0; + while (Z_TYPE_PP(args[i++]) != IS_STRING) { + if (i >= ZEND_NUM_ARGS()) { + _php_ibase_module_error("Query argument missing" TSRMLS_CC); + goto ibase_query_end; + + } + } + + convert_to_string_ex(args[i-1]); + query = Z_STRVAL_PP(args[i-1]); + + /* find out if the first one or two arguments refer to either a link id, + a trans id or both */ + switch (i) { + case 1: + + /* no link ids were passed: if there's no default link, use exec_immediate() with + a NULL handle; this will enable the use of CREATE DATABASE statements. */ + if (IBG(default_link) == -1) { + isc_db_handle db = NULL; + isc_tr_handle trans = NULL; + + if (isc_dsql_execute_immediate(IB_STATUS, &db, &trans, 0, query, + SQL_DIALECT_CURRENT, NULL)) { + _php_ibase_error(TSRMLS_C); + goto ibase_query_end; + } + + /* has a new database been created ? */ + if (db != NULL) { + + if ((IBG(max_links) != -1) && (IBG(num_links) >= IBG(max_links))) { + + /* too many links already ? => close it up immediately */ + if (isc_detach_database(IB_STATUS, &db)) { + _php_ibase_error(TSRMLS_C); + goto ibase_query_end; + } + } else { + + /* register the link as a resource; unfortunately, we cannot register + it in the hash table, because we don't know the connection params */ + ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link)); + ib_link->handle = db; + ib_link->dialect = SQL_DIALECT_CURRENT; + ib_link->tr_list = NULL; + ib_link->event_head = NULL; + + ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link); + zend_list_addref(Z_LVAL_P(return_value)); + IBG(default_link) = Z_LVAL_P(return_value); + IBG(num_links)++; + goto ibase_query_end; + } + } + RETURN_TRUE; + } + + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", + le_link, le_plink); + break; + case 2: + /* one id was passed, could be db or trans id */ + _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, args[0], &ib_link, &trans); + + if (trans != NULL) { + /* argument was a trans id */ + convert_to_long_ex(args[0]); + trans_res_id = Z_LVAL_PP(args[0]); + } + break; + case 3: + /* two ids were passed, first should be link and second should be trans; */ + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, args[0], -1, "InterBase link", + le_link, le_plink); + ZEND_FETCH_RESOURCE(trans, ibase_trans*, args[1], -1, "InterBase transaction", le_trans); + + convert_to_long_ex(args[1]); + trans_res_id = Z_LVAL_PP(args[1]); + + break; + default: + /* more than two arguments preceed the SQL string */ + _php_ibase_module_error("Invalid arguments" TSRMLS_CC); + goto ibase_query_end; + } + + if (ZEND_NUM_ARGS() > i) { /* have variables to bind */ + bind_n = ZEND_NUM_ARGS() - i; + bind_args = args[i]; + } + + /* open default transaction */ + if (ib_link == NULL || _php_ibase_def_trans(ib_link, &trans TSRMLS_CC) == FAILURE) { + goto ibase_query_end; + } + + if (FAILURE == _php_ibase_alloc_query(&ib_query, ib_link, trans, query, ib_link->dialect, + trans_res_id TSRMLS_CC)) { + goto ibase_query_end; + } + + do { + if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, &ib_query, + bind_n, bind_args)) { + break; + } + + if (result != NULL) { /* statement returns a result */ + result->type = QUERY_RESULT; + + /* EXECUTE PROCEDURE returns only one row => statement can be released immediately */ + if (ib_query.statement_type != isc_info_sql_stmt_exec_procedure) { + ib_query.stmt = NULL; /* keep stmt when free query */ + } + ZEND_REGISTER_RESOURCE(return_value, result, le_result); + } + } while (0); + _php_ibase_free_query(&ib_query TSRMLS_CC); + +ibase_query_end: + free_alloca(args); +} +/* }}} */ + +/* {{{ proto int ibase_affected_rows( [ resource link_identifier ] ) + Returns the number of rows affected by the previous INSERT, UPDATE or DELETE statement */ +PHP_FUNCTION(ibase_affected_rows) +{ + ibase_trans *trans = NULL; + + RESET_ERRMSG; + + switch (ZEND_NUM_ARGS()) { + + ibase_db_link *ib_link; + zval **arg; + + case 0: + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", + le_link, le_plink); + if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { + RETURN_FALSE; + } + trans = ib_link->tr_list->trans; + break; + + case 1: + if (zend_get_parameters_ex(1, &arg) == FAILURE) { + RETURN_FALSE; + } + /* one id was passed, could be db or trans id */ + _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, arg, &ib_link, &trans); + if (trans == NULL) { + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, arg, -1, "InterBase link", + le_link, le_plink); + + if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { + RETURN_FALSE; + } + trans = ib_link->tr_list->trans; + } + break; + + default: + WRONG_PARAM_COUNT; + break; + } + RETURN_LONG(trans->affected_rows); +} +/* }}} */ + +/* {{{ proto int ibase_num_rows( resource result_identifier ) + Return the number of rows that are available in a result */ +#if abies_0 +PHP_FUNCTION(ibase_num_rows) +{ + /** + * As this function relies on the InterBase API function isc_dsql_sql_info() + * which has a couple of limitations (which I hope will be fixed in future + * releases of Firebird), this function is fairly useless. I'm leaving it + * in place for people who can live with the limitations, which I only + * found out about after I had implemented it anyway. + * + * Currently, there's no way to determine how many rows can be fetched from + * a cursor. The only number that _can_ be determined is the number of rows + * that have already been pre-fetched by the client library. + * This implies the following: + * - num_rows() always returns zero before the first fetch; + * - num_rows() for SELECT ... FOR UPDATE is broken -> never returns a + * higher number than the number of records fetched so far (no pre-fetch); + * - the result of num_rows() for other statements is merely a lower bound + * on the number of records => calling ibase_num_rows() again after a couple + * of fetches will most likely return a new (higher) figure for large result + * sets. + */ + + zval **result_arg; + ibase_result *ib_result; + static char info_count[] = {isc_info_sql_records}; + char result[64]; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result_arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); + + if (isc_dsql_sql_info(IB_STATUS, &ib_result->stmt, sizeof(info_count), info_count, + sizeof(result), result)) { + _php_ibase_error(TSRMLS_C); + RETURN_FALSE; + } + + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1],2); + + while (result[i] != isc_info_end && i < result_size) { + short len = (short)isc_vax_integer(&result[i+1],2); + if (result[i] == isc_info_req_select_count) { + RETURN_LONG(isc_vax_integer(&result[i+3],len)); + } + i += len+3; + } + } +} +#endif +/* }}} */ + +static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ */ + int scale, int flag TSRMLS_DC) +{ +#ifdef SQL_INT64 + static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000, + 1000000000, LL_LIT(10000000000),LL_LIT(100000000000),LL_LIT(10000000000000),LL_LIT(100000000000000), + LL_LIT(1000000000000000),LL_LIT(1000000000000000),LL_LIT(1000000000000000000) }; +#else + static long const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000, + 1000000000 }; +#endif + + switch (type & ~1) { + unsigned short l; + long n; + char string_data[255]; + struct tm t; + char *format; + + case SQL_VARYING: + len = ((IBVARY *) data)->vary_length; + data = ((IBVARY *) data)->vary_string; + /* no break */ + case SQL_TEXT: + if (PG(magic_quotes_runtime)) { + Z_STRVAL_P(val) = php_addslashes(data, len, &Z_STRLEN_P(val), 0 TSRMLS_CC); + Z_TYPE_P(val) = IS_STRING; + } else { + ZVAL_STRINGL(val,(char *) data,len,1); + } + break; + case SQL_SHORT: + n = *(short *) data; + goto _sql_long; +#ifdef SQL_INT64 + case SQL_INT64: +#if (SIZEOF_LONG >= 8) + n = *(long *) data; + goto _sql_long; +#else + if (scale == 0) { + l = sprintf(string_data, "%" LL_MASK "d", *(ISC_INT64 *) data); + ZVAL_STRINGL(val,string_data,l,1); + } else { + ISC_INT64 n = *(ISC_INT64 *) data, f = scales[-scale]; + + if (n >= 0) { + l = sprintf(string_data, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, n % f); + } else if (n < -f) { + l = sprintf(string_data, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, -n % f); + } else { + l = sprintf(string_data, "-0.%0*" LL_MASK "d", -scale, -n % f); + } + ZVAL_STRINGL(val,string_data,l,1); + } + break; +#endif +#endif + case SQL_LONG: + n = *(ISC_LONG *) data; + _sql_long: + if (scale == 0) { + ZVAL_LONG(val,n); + } else { + long f = (long) scales[-scale]; + + if (n >= 0) { + l = sprintf(string_data, "%ld.%0*ld", n / f, -scale, n % f); + } else if (n < -f) { + l = sprintf(string_data, "%ld.%0*ld", n / f, -scale, -n % f); + } else { + l = sprintf(string_data, "-0.%0*ld", -scale, -n % f); + } + ZVAL_STRINGL(val,string_data,l,1); + } + break; + case SQL_FLOAT: + ZVAL_DOUBLE(val, *(float *) data); + break; + case SQL_DOUBLE: + ZVAL_DOUBLE(val, *(double *) data); + break; + case SQL_DATE: /* == case SQL_TIMESTAMP: */ + format = IBG(timestampformat); +#ifndef SQL_TIMESTAMP + isc_decode_date((ISC_QUAD *) data, &t); +#else + isc_decode_timestamp((ISC_TIMESTAMP *) data, &t); + goto format_date_time; + case SQL_TYPE_DATE: + format = IBG(dateformat); + isc_decode_sql_date((ISC_DATE *) data, &t); + goto format_date_time; + case SQL_TYPE_TIME: + format = IBG(timeformat); + isc_decode_sql_time((ISC_TIME *) data, &t); + +format_date_time: +#endif + /* + XXX - Might have to remove this later - seems that isc_decode_date() + always sets tm_isdst to 0, sometimes incorrectly (InterBase 6 bug?) + */ + t.tm_isdst = -1; +#if HAVE_TM_ZONE + t.tm_zone = tzname[0]; +#endif + if (flag & PHP_IBASE_UNIXTIME) { + ZVAL_LONG(val, mktime(&t)); + } else { +#if HAVE_STRFTIME + l = strftime(string_data, sizeof(string_data), format, &t); +#else + switch (type & ~1) { + default: + l = sprintf(string_data, "%02d/%02d/%4d %02d:%02d:%02d", t.tm_mon+1, t.tm_mday, + t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec); + break; +#ifdef SQL_TIMESTAMP + case SQL_TYPE_DATE: + l = sprintf(string_data, "%02d/%02d/%4d", t.tm_mon + 1, t.tm_mday, t.tm_year+1900); + break; + case SQL_TYPE_TIME: + l = sprintf(string_data, "%02d:%02d:%02d", t.tm_hour, t.tm_min, t.tm_sec); + break; +#endif + } +#endif + ZVAL_STRINGL(val,string_data,l,1); + break; + } + } /* switch (type) */ + return SUCCESS; +} +/* }}} */ + +static int _php_ibase_arr_zval(zval *ar_zval, char *data, unsigned long data_size, /* {{{ */ + ibase_array *ib_array, int dim, int flag TSRMLS_DC) +{ + /** + * Create multidimension array - recursion function + */ + int + u_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_upper, + l_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_lower, + dim_len = 1 + u_bound - l_bound; + unsigned short i; + + if (dim < ib_array->ar_desc.array_desc_dimensions) { /* array again */ + unsigned long slice_size = data_size / dim_len; + + array_init(ar_zval); + + for (i = 0; i < dim_len; ++i) { + zval *slice_zval; + ALLOC_INIT_ZVAL(slice_zval); + + /* recursion here */ + if (FAILURE == _php_ibase_arr_zval(slice_zval, data, slice_size, ib_array, dim + 1, + flag TSRMLS_CC)) { + return FAILURE; + } + data += slice_size; + + add_index_zval(ar_zval,l_bound+i,slice_zval); + } + } else { /* data at last */ + + if (FAILURE == _php_ibase_var_zval(ar_zval, data, ib_array->el_type, + ib_array->ar_desc.array_desc_length, ib_array->ar_desc.array_desc_scale, flag TSRMLS_CC)) { + return FAILURE; + } + + /* fix for peculiar handling of VARCHAR arrays; + truncate the field to the cstring length */ + if (ib_array->ar_desc.array_desc_dtype == blr_varying || + ib_array->ar_desc.array_desc_dtype == blr_varying2) { + + Z_STRLEN_P(ar_zval) = strlen(Z_STRVAL_P(ar_zval)); + } + } + return SUCCESS; +} +/* }}} */ + +static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type) /* {{{ */ +{ + zval **result_arg, **flag_arg; + long i, array_cnt = 0, flag = 0; + ibase_result *ib_result; + + RESET_ERRMSG; + + switch (ZEND_NUM_ARGS()) { + case 1: + if (FAILURE == zend_get_parameters_ex(1, &result_arg)) { + RETURN_FALSE; + } + break; + case 2: + if (FAILURE == zend_get_parameters_ex(2, &result_arg, &flag_arg)) { + RETURN_FALSE; + } + convert_to_long_ex(flag_arg); + flag = Z_LVAL_PP(flag_arg); + break; + default: + WRONG_PARAM_COUNT; + break; + } + + ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); + + if (ib_result->out_sqlda == NULL || !ib_result->has_more_rows) { + RETURN_FALSE; + } + + if (ib_result->statement_type != isc_info_sql_stmt_exec_procedure) { + + if (isc_dsql_fetch(IB_STATUS, &ib_result->stmt, 1, ib_result->out_sqlda)) { + + ib_result->has_more_rows = 0; + if (IB_STATUS[0] && IB_STATUS[1]) { /* error in fetch */ + _php_ibase_error(TSRMLS_C); + } + RETURN_FALSE; + } + } else { + ib_result->has_more_rows = 0; + } + + array_init(return_value); + + for (i = 0; i < ib_result->out_sqlda->sqld; ++i) { + XSQLVAR *var = &ib_result->out_sqlda->sqlvar[i]; + + if (((var->sqltype & 1) == 0) || *var->sqlind != -1) { + zval *result; + ALLOC_INIT_ZVAL(result); + + switch (var->sqltype & ~1) { + + default: + _php_ibase_var_zval(result, var->sqldata, var->sqltype, var->sqllen, + var->sqlscale, flag TSRMLS_CC); + break; + case SQL_BLOB: + if (flag & PHP_IBASE_FETCH_BLOBS) { /* fetch blob contents into hash */ + + ibase_blob blob_handle; + unsigned long max_len = 0; + static char bl_items[] = {isc_info_blob_total_length}; + char bl_info[20]; + unsigned short i; + + blob_handle.bl_handle = NULL; + blob_handle.bl_qd = *(ISC_QUAD *) var->sqldata; + + if (isc_open_blob(IB_STATUS, &ib_result->link->handle, &ib_result->trans->handle, + &blob_handle.bl_handle, &blob_handle.bl_qd)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_fetch_error; + } + + if (isc_blob_info(IB_STATUS, &blob_handle.bl_handle, sizeof(bl_items), + bl_items, sizeof(bl_info), bl_info)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_fetch_error; + } + + /* find total length of blob's data */ + for (i = 0; i < sizeof(bl_info); ) { + unsigned short item_len; + char item = bl_info[i++]; + + if (item == isc_info_end || item == isc_info_truncated || + item == isc_info_error || i >= sizeof(bl_info)) { + + _php_ibase_module_error("Could not determine BLOB size (internal error)" + TSRMLS_CC); + goto _php_ibase_fetch_error; + } + + item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2); + + if (item == isc_info_blob_total_length) { + max_len = isc_vax_integer(&bl_info[i+2], item_len); + break; + } + i += item_len+2; + } + + if (max_len == 0) { + ZVAL_STRING(result, "", 1); + } else if (SUCCESS != _php_ibase_blob_get(result, &blob_handle, + max_len TSRMLS_CC)) { + goto _php_ibase_fetch_error; + } + + if (isc_close_blob(IB_STATUS, &blob_handle.bl_handle)) { + _php_ibase_error(TSRMLS_C); + goto _php_ibase_fetch_error; + } + + } else { /* blob id only */ + ISC_QUAD bl_qd = *(ISC_QUAD *) var->sqldata; + ZVAL_STRINGL(result,_php_ibase_quad_to_string(bl_qd), BLOB_ID_LEN, 0); + } + break; + case SQL_ARRAY: + if (flag & PHP_IBASE_FETCH_ARRAYS) { /* array can be *huge* so only fetch if asked */ + ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata; + ibase_array *ib_array = &ib_result->out_array[array_cnt++]; + void *ar_data = emalloc(ib_array->ar_size); + + if (isc_array_get_slice(IB_STATUS, &ib_result->link->handle, + &ib_result->trans->handle, &ar_qd, &ib_array->ar_desc, + ar_data, &ib_array->ar_size)) { + _php_ibase_error(TSRMLS_C); + efree(ar_data); + goto _php_ibase_fetch_error; + } + + if (FAILURE == _php_ibase_arr_zval(result, ar_data, ib_array->ar_size, ib_array, + 0, flag TSRMLS_CC)) { + efree(ar_data); + goto _php_ibase_fetch_error; + } + efree(ar_data); + + } else { /* blob id only */ + ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata; + ZVAL_STRINGL(result,_php_ibase_quad_to_string(ar_qd), BLOB_ID_LEN, 0); + } + break; + _php_ibase_fetch_error: + zval_dtor(result); + FREE_ZVAL(result); + RETURN_FALSE; + } /* switch */ + + if (fetch_type & FETCH_ROW) { + add_index_zval(return_value, i, result); + } else { + add_assoc_zval(return_value, var->aliasname, result); + } + } else { + if (fetch_type & FETCH_ROW) { + add_index_null(return_value, i); + } else { + add_assoc_null(return_value, var->aliasname); + } + } + } /* for field */ +} +/* }}} */ + +/* {{{ proto array ibase_fetch_row(resource result [, int fetch_flags]) + Fetch a row from the results of a query */ +PHP_FUNCTION(ibase_fetch_row) +{ + _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ROW); +} +/* }}} */ + +/* {{{ proto array ibase_fetch_assoc(resource result [, int fetch_flags]) + Fetch a row from the results of a query */ +PHP_FUNCTION(ibase_fetch_assoc) +{ + _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY); +} +/* }}} */ + +/* {{{ proto object ibase_fetch_object(resource result [, int fetch_flags]) + Fetch a object from the results of a query */ +PHP_FUNCTION(ibase_fetch_object) +{ + _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY); + + if (Z_TYPE_P(return_value) == IS_ARRAY) { + object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value)); + } +} +/* }}} */ + + +/* {{{ proto bool ibase_name_result(resource result, string name) + Assign a name to a result for use with ... WHERE CURRENT OF statements */ +PHP_FUNCTION(ibase_name_result) +{ + zval **result_arg, **name_arg; + ibase_result *ib_result; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result_arg, &name_arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); + convert_to_string_ex(name_arg); + + if (isc_dsql_set_cursor_name(IB_STATUS, &ib_result->stmt, Z_STRVAL_PP(name_arg), 0)) { + _php_ibase_error(TSRMLS_C); + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + + +/* {{{ proto bool ibase_free_result(resource result) + Free the memory used by a result */ +PHP_FUNCTION(ibase_free_result) +{ + zval **result_arg; + ibase_result *ib_result; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result_arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); + zend_list_delete(Z_LVAL_PP(result_arg)); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto resource ibase_prepare([resource link_identifier, ] string query) + Prepare a query for later execution */ +PHP_FUNCTION(ibase_prepare) +{ + zval **link_arg, **trans_arg, **query_arg; + ibase_db_link *ib_link; + ibase_trans *trans = NULL; + int trans_res_id = 0; + ibase_query *ib_query; + char *query; + + RESET_ERRMSG; + + switch (ZEND_NUM_ARGS()) { + case 1: + if (zend_get_parameters_ex(1, &query_arg) == FAILURE) { + RETURN_FALSE; + } + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", + le_link, le_plink); + break; + case 2: + if (zend_get_parameters_ex(2, &link_arg, &query_arg) == FAILURE) { + RETURN_FALSE; + } + _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, link_arg, &ib_link, &trans); + + if (trans != NULL) { + convert_to_long_ex(link_arg); + trans_res_id = Z_LVAL_PP(link_arg); + } + + break; + case 3: + if (zend_get_parameters_ex(3, &link_arg, &trans_arg, &query_arg) == FAILURE) { + RETURN_FALSE; + } + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, link_arg, -1, "InterBase link", + le_link, le_plink); + ZEND_FETCH_RESOURCE(trans, ibase_trans*, trans_arg, -1, "InterBase transaction", le_trans); + + convert_to_long_ex(trans_arg); + trans_res_id = Z_LVAL_PP(trans_arg); + + break; + default: + WRONG_PARAM_COUNT; + break; + } + + convert_to_string_ex(query_arg); + query = Z_STRVAL_PP(query_arg); + + if (FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC)) { + RETURN_FALSE; + } + + ib_query = (ibase_query *) emalloc(sizeof(ibase_query)); + + if (FAILURE == _php_ibase_alloc_query(ib_query, ib_link, trans, query, ib_link->dialect, + trans_res_id TSRMLS_CC)) { + efree(ib_query); + RETURN_FALSE; + } + ZEND_REGISTER_RESOURCE(return_value, ib_query, le_query); +} +/* }}} */ + +/* {{{ proto mixed ibase_execute(resource query [, mixed bind_arg [, mixed bind_arg [, ...]]]) + Execute a previously prepared query */ +PHP_FUNCTION(ibase_execute) +{ + zval ***args, **bind_args = NULL; + ibase_query *ib_query; + ibase_result *result = NULL; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() < 1) { + WRONG_PARAM_COUNT; + } + + /* use stack to avoid leaks */ + args = (zval ***) do_alloca(ZEND_NUM_ARGS() * sizeof(zval **)); + if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + free_alloca(args); + RETURN_FALSE; + } + + ZEND_FETCH_RESOURCE(ib_query, ibase_query *, args[0], -1, "InterBase query", le_query); + + if (ZEND_NUM_ARGS() > 1) { /* have variables to bind */ + bind_args = args[1]; + } + + /* Have we used this cursor before and it's still open (exec proc has no cursor) ? */ + if (ib_query->result_res_id != 0 && ib_query->statement_type != isc_info_sql_stmt_exec_procedure) { + IBDEBUG("Implicitly closing a cursor"); + if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_close)) { + _php_ibase_error(TSRMLS_C); + } + /* invalidate previous results returned by this query (not necessary for exec proc) */ + zend_list_delete(ib_query->result_res_id); + } + + if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, ib_query, + ZEND_NUM_ARGS()-1, bind_args)) { + free_alloca(args); + RETURN_FALSE; + } + + /* free the query if trans handle was released */ + if (ib_query->trans->handle == NULL) { + zend_list_delete(Z_LVAL_PP(args[0])); + } + + free_alloca(args); + + if (result != NULL) { + result->type = EXECUTE_RESULT; + if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) { + result->stmt = NULL; + } + ib_query->result_res_id = zend_list_insert(result, le_result); + RETURN_RESOURCE(ib_query->result_res_id); + } +} +/* }}} */ + +/* {{{ proto bool ibase_free_query(resource query) + Free memory used by a query */ +PHP_FUNCTION(ibase_free_query) +{ + zval **query_arg; + ibase_query *ib_query; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &query_arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(ib_query, ibase_query *, query_arg, -1, "InterBase query", le_query); + zend_list_delete(Z_LVAL_PP(query_arg)); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int ibase_num_fields(resource query_result) + Get the number of fields in result */ +PHP_FUNCTION(ibase_num_fields) +{ + zval **result; + int type; + XSQLDA *sqlda; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + zend_list_find(Z_LVAL_PP(result), &type); + + if (type == le_query) { + ibase_query *ib_query; + + ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result, -1, "InterBase query", le_query); + sqlda = ib_query->out_sqlda; + } else { + ibase_result *ib_result; + + ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result, -1, "InterBase result", le_result); + sqlda = ib_result->out_sqlda; + } + + if (sqlda == NULL) { + RETURN_LONG(0); + } else { + RETURN_LONG(sqlda->sqld); + } +} +/* }}} */ + +static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */ +{ + unsigned short len; + char buf[16], *s = buf; + + array_init(return_value); + + add_index_stringl(return_value, 0, var->sqlname, var->sqlname_length, 1); + add_assoc_stringl(return_value, "name", var->sqlname, var->sqlname_length, 1); + + add_index_stringl(return_value, 1, var->aliasname, var->aliasname_length, 1); + add_assoc_stringl(return_value, "alias", var->aliasname, var->aliasname_length, 1); + + add_index_stringl(return_value, 2, var->relname, var->relname_length, 1); + add_assoc_stringl(return_value, "relation", var->relname, var->relname_length, 1); + + len = sprintf(buf, "%d", var->sqllen); + add_index_stringl(return_value, 3, buf, len, 1); + add_assoc_stringl(return_value, "length", buf, len, 1); + + if (var->sqlscale < 0) { + unsigned short precision = 0; + + switch (var->sqltype & ~1) { + + case SQL_SHORT: + precision = 4; + break; + case SQL_LONG: + precision = 9; + break; +#ifdef SQL_INT64 + case SQL_INT64: + precision = 18; + break; +#endif + } + len = sprintf(buf, "NUMERIC(%d,%d)", precision, -var->sqlscale); + add_index_stringl(return_value, 4, s, len, 1); + add_assoc_stringl(return_value, "type", s, len, 1); + } else { + switch (var->sqltype & ~1) { + case SQL_TEXT: + s = "CHAR"; + break; + case SQL_VARYING: + s = "VARCHAR"; + break; + case SQL_SHORT: + s = "SMALLINT"; + break; + case SQL_LONG: + s = "INTEGER"; + break; + case SQL_FLOAT: + s = "FLOAT"; break; + case SQL_DOUBLE: + case SQL_D_FLOAT: + s = "DOUBLE PRECISION"; break; +#ifdef SQL_INT64 + case SQL_INT64: + s = "BIGINT"; + break; +#endif +#ifdef SQL_TIMESTAMP + case SQL_TIMESTAMP: + s = "TIMESTAMP"; + break; + case SQL_TYPE_DATE: + s = "DATE"; + break; + case SQL_TYPE_TIME: + s = "TIME"; + break; +#else + case SQL_DATE: + s = "DATE"; + break; +#endif + case SQL_BLOB: + s = "BLOB"; + break; + case SQL_ARRAY: + s = "ARRAY"; + break; + /* FIXME: provide more detailed information about the field type, field size + * and array dimensions */ + case SQL_QUAD: + s = "QUAD"; + break; + } + add_index_string(return_value, 4, s, 1); + add_assoc_string(return_value, "type", s, 1); + } +} +/* }}} */ + +/* {{{ proto array ibase_field_info(resource query_result, int field_number) + Get information about a field */ +PHP_FUNCTION(ibase_field_info) +{ + zval **result_arg, **field_arg; + int type; + XSQLDA *sqlda; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &result_arg, &field_arg)==FAILURE) { + WRONG_PARAM_COUNT; + } + + zend_list_find(Z_LVAL_PP(result_arg), &type); + + if (type == le_query) { + ibase_query *ib_query; + + ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result_arg, -1, "InterBase query", le_query); + sqlda = ib_query->out_sqlda; + } else { + ibase_result *ib_result; + + ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); + sqlda = ib_result->out_sqlda; + } + + if (sqlda == NULL) { + _php_ibase_module_error("Trying to get field info from a non-select query" TSRMLS_CC); + RETURN_FALSE; + } + + convert_to_long_ex(field_arg); + + if (Z_LVAL_PP(field_arg) < 0 || Z_LVAL_PP(field_arg) >= sqlda->sqld) { + RETURN_FALSE; + } + _php_ibase_field_info(return_value,sqlda->sqlvar + Z_LVAL_PP(field_arg)); +} +/* }}} */ + +/* {{{ proto int ibase_num_params(resource query) + Get the number of params in a prepared query */ +PHP_FUNCTION(ibase_num_params) +{ + zval **result; + ibase_query *ib_query; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result, -1, "InterBase query", le_query); + + if (ib_query->in_sqlda == NULL) { + RETURN_LONG(0); + } else { + RETURN_LONG(ib_query->in_sqlda->sqld); + } +} +/* }}} */ + +/* {{{ proto array ibase_param_info(resource query, int field_number) + Get information about a parameter */ +PHP_FUNCTION(ibase_param_info) +{ + zval **result_arg, **field_arg; + ibase_query *ib_query; + + RESET_ERRMSG; + + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result_arg, &field_arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result_arg, -1, "InterBase query", le_query); + + if (ib_query->in_sqlda == NULL) { + RETURN_FALSE; + } + + convert_to_long_ex(field_arg); + + if (Z_LVAL_PP(field_arg) < 0 || Z_LVAL_PP(field_arg) >= ib_query->in_sqlda->sqld) { + RETURN_FALSE; + } + + _php_ibase_field_info(return_value,ib_query->in_sqlda->sqlvar + Z_LVAL_PP(field_arg)); +} +/* }}} */ + +#endif /* HAVE_IBASE */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/ext/interbase/ibase_service.c b/ext/interbase/ibase_service.c index 147ee4688fd..6f564b3fb65 100644 --- a/ext/interbase/ibase_service.c +++ b/ext/interbase/ibase_service.c @@ -29,6 +29,97 @@ #include "php_interbase.h" #include "php_ibase_includes.h" +static int le_service; + +static void _php_ibase_free_service(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_service *sv = (ibase_service *) rsrc->ptr; + + if (isc_service_detach(IB_STATUS, &sv->handle)) { + _php_ibase_error(TSRMLS_C); + } + + if (sv->hostname) { + efree(sv->hostname); + } + if (sv->username) { + efree(sv->username); + } + + efree(sv); +} +/* }}} */ + +void php_ibase_service_minit(INIT_FUNC_ARGS) /* {{{ */ +{ + le_service = zend_register_list_destructors_ex(_php_ibase_free_service, NULL, + "interbase service manager handle", module_number); + + /* backup options */ + REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_CHECKSUMS", isc_spb_bkp_ignore_checksums, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_LIMBO", isc_spb_bkp_ignore_limbo, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_BKP_METADATA_ONLY", isc_spb_bkp_metadata_only, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_BKP_NO_GARBAGE_COLLECT", isc_spb_bkp_no_garbage_collect, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_BKP_OLD_DESCRIPTIONS", isc_spb_bkp_old_descriptions, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_BKP_NON_TRANSPORTABLE", isc_spb_bkp_non_transportable, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_BKP_CONVERT", isc_spb_bkp_convert, CONST_PERSISTENT); + + /* restore options */ + REGISTER_LONG_CONSTANT("IBASE_RES_DEACTIVATE_IDX", isc_spb_res_deactivate_idx, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RES_NO_SHADOW", isc_spb_res_no_shadow, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RES_NO_VALIDITY", isc_spb_res_no_validity, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RES_ONE_AT_A_TIME", isc_spb_res_one_at_a_time, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RES_REPLACE", isc_spb_res_replace, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RES_CREATE", isc_spb_res_create, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RES_USE_ALL_SPACE", isc_spb_res_use_all_space, CONST_PERSISTENT); + + /* manage options */ + REGISTER_LONG_CONSTANT("IBASE_PRP_PAGE_BUFFERS", isc_spb_prp_page_buffers, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_SWEEP_INTERVAL", isc_spb_prp_sweep_interval, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_SHUTDOWN_DB", isc_spb_prp_shutdown_db, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_TRANSACTIONS", isc_spb_prp_deny_new_transactions, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_ATTACHMENTS", isc_spb_prp_deny_new_attachments, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_RESERVE_SPACE", isc_spb_prp_reserve_space, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_RES_USE_FULL", isc_spb_prp_res_use_full, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_RES", isc_spb_prp_res, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_WRITE_MODE", isc_spb_prp_write_mode, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_WM_ASYNC", isc_spb_prp_wm_async, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_WM_SYNC", isc_spb_prp_wm_sync, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_ACCESS_MODE", isc_spb_prp_access_mode, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READONLY", isc_spb_prp_am_readonly, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READWRITE", isc_spb_prp_am_readwrite, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_SET_SQL_DIALECT", isc_spb_prp_set_sql_dialect, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_ACTIVATE", isc_spb_prp_activate, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_PRP_DB_ONLINE", isc_spb_prp_db_online, CONST_PERSISTENT); + + /* repair options */ + REGISTER_LONG_CONSTANT("IBASE_RPR_CHECK_DB", isc_spb_rpr_check_db, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RPR_IGNORE_CHECKSUM", isc_spb_rpr_ignore_checksum, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RPR_KILL_SHADOWS", isc_spb_rpr_kill_shadows, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RPR_MEND_DB", isc_spb_rpr_mend_db, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RPR_VALIDATE_DB", isc_spb_rpr_validate_db, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RPR_FULL", isc_spb_rpr_full, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_RPR_SWEEP_DB", isc_spb_rpr_sweep_db, CONST_PERSISTENT); + + /* db info arguments */ + REGISTER_LONG_CONSTANT("IBASE_STS_DATA_PAGES", isc_spb_sts_data_pages, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_STS_DB_LOG", isc_spb_sts_db_log, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_STS_HDR_PAGES", isc_spb_sts_hdr_pages, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_STS_IDX_PAGES", isc_spb_sts_idx_pages, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_STS_SYS_RELATIONS", isc_spb_sts_sys_relations, CONST_PERSISTENT); + + /* server info arguments */ + REGISTER_LONG_CONSTANT("IBASE_SVC_SERVER_VERSION", isc_info_svc_server_version, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_IMPLEMENTATION", isc_info_svc_implementation, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV", isc_info_svc_get_env, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_LOCK", isc_info_svc_get_env_lock, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_MSG", isc_info_svc_get_env_msg, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_USER_DBPATH", isc_info_svc_user_dbpath, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_SVR_DB_INFO", isc_info_svc_svr_db_info, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_SVC_GET_USERS", isc_info_svc_get_users, CONST_PERSISTENT); +} +/* }}} */ + static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, int operation) /* {{{ */ { zval **args[8]; @@ -38,7 +129,7 @@ static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, int operation) /* {{{ char spb_buffer[128], *spb = spb_buffer; unsigned short spb_length; isc_svc_handle service_handle = NULL; - + RESET_ERRMSG; switch (operation) { @@ -49,7 +140,7 @@ static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, int operation) /* {{{ WRONG_PARAM_COUNT; } break; - + case isc_action_svc_delete_user: /* 4 parameters for DELETE operation */ if (ZEND_NUM_ARGS() != 4) { @@ -161,7 +252,7 @@ static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, int operation) /* {{{ isc_service_detach(IB_STATUS, &service_handle); } } - + RETURN_TRUE; } /* }}} */ @@ -190,7 +281,7 @@ PHP_FUNCTION(ibase_delete_user) } /* }}} */ -/* {{{ proto resource ibase_service_attach(string host, string dba_username, string dba_password) +/* {{{ proto resource ibase_service_attach(string host, string dba_username, string dba_password) Connect to the service manager */ PHP_FUNCTION(ibase_service_attach) { @@ -200,33 +291,33 @@ PHP_FUNCTION(ibase_service_attach) isc_svc_handle handle = NULL; RESET_ERRMSG; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &host, &hlen, &user, &ulen, &pass, &plen)) { - + RETURN_FALSE; } /* construct the spb, hack the service name into it as well */ - spb_len = snprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%s" "%s:service_mgr", + spb_len = snprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%s" "%s:service_mgr", isc_spb_version, isc_spb_current_version, isc_spb_user_name, (char)ulen, user, isc_spb_password, (char)plen, pass, host); if (spb_len > sizeof(buf) || spb_len == -1) { - _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%ld)" + _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%ld)" TSRMLS_CC, spb_len); RETURN_FALSE; } - + spb_len -= hlen + 12; loc = buf + spb_len; /* points to %s:service_mgr part */ - + /* attach to the service manager */ if (isc_service_attach(IB_STATUS, 0, loc, &handle, (unsigned short)spb_len, buf)) { _php_ibase_error(TSRMLS_C); RETURN_FALSE; } - + svm = (ibase_service*)emalloc(sizeof(ibase_service)); svm->handle = handle; svm->hostname = estrdup(host); @@ -237,20 +328,20 @@ PHP_FUNCTION(ibase_service_attach) } /* }}} */ -/* {{{ proto bool ibase_service_detach(resource service_handle) +/* {{{ proto bool ibase_service_detach(resource service_handle) Disconnect from the service manager */ PHP_FUNCTION(ibase_service_detach) { zval *res; - + RESET_ERRMSG; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &res)) { - RETURN_FALSE; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &res)) { + RETURN_FALSE; } - + zend_list_delete(Z_LVAL_P(res)); - + RETURN_TRUE; } /* }}} */ @@ -259,7 +350,7 @@ static void _php_ibase_service_query(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */ ibase_service *svm, char info_action) { static char spb[] = { isc_info_svc_timeout, 10, 0, 0, 0 }; - + char res_buf[400], *result, *heap_buf = NULL, *heap_p; long heap_buf_size = 200, line_len; @@ -272,13 +363,13 @@ static void _php_ibase_service_query(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */ RETURN_FALSE; } } - -query_loop: + +query_loop: result = res_buf; if (isc_service_query(IB_STATUS, &svm->handle, NULL, sizeof(spb), spb, 1, &info_action, sizeof(res_buf), res_buf)) { - + _php_ibase_error(TSRMLS_C); RETURN_FALSE; } @@ -286,8 +377,8 @@ query_loop: switch (*result++) { default: RETURN_FALSE; - - case isc_info_svc_line: + + case isc_info_svc_line: if (! (line_len = isc_vax_integer(result, 2))) { /* done */ if (heap_buf) { @@ -298,9 +389,9 @@ query_loop: } if (!heap_buf || (heap_p - heap_buf + line_len +2) > heap_buf_size) { long res_size = heap_buf ? heap_p - heap_buf : 0; - + while (heap_buf_size < (res_size + line_len +2)) { - heap_buf_size *= 2; + heap_buf_size *= 2; } heap_buf = (char*) erealloc(heap_buf, heap_buf_size); heap_p = heap_buf + res_size; @@ -316,7 +407,7 @@ query_loop: case isc_info_svc_get_env_lock: case isc_info_svc_get_env_msg: case isc_info_svc_user_dbpath: - RETURN_STRINGL(result + 2, isc_vax_integer(result, 2), 1); + RETURN_STRINGL(result + 2, isc_vax_integer(result, 2), 1); case isc_info_svc_svr_db_info: array_init(return_value); @@ -329,7 +420,7 @@ query_loop: add_assoc_long(return_value, "attachments", isc_vax_integer(result,4)); result += 4; break; - + case isc_spb_num_db: add_assoc_long(return_value, "databases", isc_vax_integer(result,4)); result += 4; @@ -342,16 +433,16 @@ query_loop: } } while (*result != isc_info_flag_end); return; - + case isc_info_svc_get_users: { zval *user; array_init(return_value); - + while (*result != isc_info_end) { - + switch (*result++) { int len; - + case isc_spb_sec_username: /* it appears that the username is always first */ ALLOC_INIT_ZVAL(user); @@ -362,7 +453,7 @@ query_loop: add_assoc_stringl(user, "user_name", result +2, len, 1); result += len+2; break; - + case isc_spb_sec_firstname: len = isc_vax_integer(result,2); add_assoc_stringl(user, "first_name", result +2, len, 1); @@ -385,14 +476,14 @@ query_loop: add_assoc_long(user, "user_id", isc_vax_integer(result, 4)); result += 4; break; - + case isc_spb_sec_groupid: add_assoc_long(user, "group_id", isc_vax_integer(result, 4)); result += 4; break; } } - return; + return; } } } @@ -404,47 +495,47 @@ static void _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAMETERS, char operati /** * It appears that the service API is a little bit confused about which flag * to use for the source and destination in the case of a restore operation. - * When passing the backup file as isc_spb_dbname and the destination db as + * When passing the backup file as isc_spb_dbname and the destination db as * bpk_file, things work well. */ zval *res; - char *db, *bk, buf[200]; + char *db, *bk, buf[200]; long dblen, bklen, spb_len, opts = 0; zend_bool verbose = 0; ibase_service *svm; - + RESET_ERRMSG; - + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss|lb", - &res, &db, &dblen, &bk, &bklen, &opts, &verbose)) { - RETURN_FALSE; + &res, &db, &dblen, &bk, &bklen, &opts, &verbose)) { + RETURN_FALSE; } - - ZEND_FETCH_RESOURCE(svm, ibase_service *, &res, -1, + + ZEND_FETCH_RESOURCE(svm, ibase_service *, &res, -1, "Interbase service manager handle", le_service); - + /* fill the param buffer */ - spb_len = snprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%s%c%c%c%c%c", - operation, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, + spb_len = snprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%s%c%c%c%c%c", + operation, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, isc_spb_bkp_file, (char)bklen, (char)(bklen >> 8), bk, isc_spb_options, (char)opts,(char)(opts >> 8), (char)(opts >> 16), (char)(opts >> 24)); - + if (verbose) { buf[spb_len++] = isc_spb_verbose; } if (spb_len > sizeof(buf) || spb_len <= 0) { - _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%ld)" + _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%ld)" TSRMLS_CC, spb_len); RETURN_FALSE; } - + /* now start the backup/restore job */ if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) { _php_ibase_error(TSRMLS_C); RETURN_FALSE; } - + if (!verbose) { RETURN_TRUE; } else { @@ -475,22 +566,22 @@ static void _php_ibase_service_action(INTERNAL_FUNCTION_PARAMETERS, char svc_act char buf[128], *db; long action, spb_len, dblen, argument = 0; ibase_service *svm; - + RESET_ERRMSG; - + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl|l", - &res, &db, &dblen, &action, &argument)) { - RETURN_FALSE; + &res, &db, &dblen, &action, &argument)) { + RETURN_FALSE; } - - ZEND_FETCH_RESOURCE(svm, ibase_service *, &res, -1, + + ZEND_FETCH_RESOURCE(svm, ibase_service *, &res, -1, "Interbase service manager handle", le_service); - + if (svc_action == isc_action_svc_db_stats) { switch (action) { default: goto unknown_option; - + case isc_spb_sts_data_pages: case isc_spb_sts_db_log: case isc_spb_sts_hdr_pages: @@ -502,10 +593,10 @@ static void _php_ibase_service_action(INTERNAL_FUNCTION_PARAMETERS, char svc_act /* these actions all expect different types of arguments */ switch (action) { default: -unknown_option: +unknown_option: _php_ibase_module_error("Unrecognised option (%ld)" TSRMLS_CC, action); RETURN_FALSE; - + case isc_spb_rpr_check_db: case isc_spb_rpr_ignore_checksum: case isc_spb_rpr_kill_shadows: @@ -513,13 +604,13 @@ unknown_option: case isc_spb_rpr_validate_db: case isc_spb_rpr_sweep_db: svc_action = isc_action_svc_repair; - + case isc_spb_prp_activate: case isc_spb_prp_db_online: -options_argument: +options_argument: argument |= action; action = isc_spb_options; - + case isc_spb_prp_page_buffers: case isc_spb_prp_sweep_interval: case isc_spb_prp_shutdown_db: @@ -527,22 +618,22 @@ options_argument: case isc_spb_prp_deny_new_attachments: case isc_spb_prp_set_sql_dialect: spb_len = snprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%c%c", - svc_action, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, + svc_action, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, (char)action, (char)argument, (char)(argument >> 8), (char)(argument >> 16), (char)(argument >> 24)); break; - + case isc_spb_prp_reserve_space: case isc_spb_prp_write_mode: case isc_spb_prp_access_mode: spb_len = snprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c", - isc_action_svc_properties, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), + isc_action_svc_properties, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, (char)action, (char)argument); } } - + if (spb_len > sizeof(buf) || spb_len == -1) { - _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%ld)" + _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%ld)" TSRMLS_CC, spb_len); RETURN_FALSE; } @@ -551,14 +642,14 @@ options_argument: _php_ibase_error(TSRMLS_C); RETURN_FALSE; } - + if (svc_action == isc_action_svc_db_stats) { _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line); } else { RETURN_TRUE; } -} -/* }}} */ +} +/* }}} */ /* {{{ proto bool ibase_maintain_db(resource service_handle, string db, int action [, int argument]) Execute a maintenance command on the database server */ @@ -577,29 +668,33 @@ PHP_FUNCTION(ibase_db_info) /* }}} */ /* {{{ proto string ibase_server_info(resource service_handle, int action) - Request information about a database */ + Request information about a database server */ PHP_FUNCTION(ibase_server_info) { zval *res; long action; ibase_service *svm; - + RESET_ERRMSG; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &res, &action)) { - RETURN_FALSE; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &res, &action)) { + RETURN_FALSE; } - - ZEND_FETCH_RESOURCE(svm, ibase_service *, &res, -1, + + ZEND_FETCH_RESOURCE(svm, ibase_service *, &res, -1, "Interbase service manager handle", le_service); - + _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, (char)action); } /* }}} */ +#else + +void php_ibase_register_service_constants(INIT_FUNC_ARGS) { /* nop */ } + #endif /* HAVE_IBASE6_API */ - -/* + +/* * Local variables: * tab-width: 4 * c-basic-offset: 4 diff --git a/ext/interbase/interbase.c b/ext/interbase/interbase.c index 305e94c0cbb..d2eadb92c5a 100644 --- a/ext/interbase/interbase.c +++ b/ext/interbase/interbase.c @@ -42,27 +42,10 @@ #include -#ifdef ZEND_DEBUG_ -#define IBDEBUG(a) php_printf("::: %s (%d)\n", a, __LINE__); -#endif - -#ifndef IBDEBUG -#define IBDEBUG(a) -#endif - -#define ISC_LONG_MIN INT_MIN -#define ISC_LONG_MAX INT_MAX - -#define QUERY_RESULT 1 -#define EXECUTE_RESULT 2 - #define ROLLBACK 0 #define COMMIT 1 #define RETAIN 2 -#define FETCH_ROW 1 -#define FETCH_ARRAY 2 - /* {{{ extension definition structures */ function_entry ibase_functions[] = { PHP_FE(ibase_connect, NULL) @@ -154,7 +137,7 @@ ZEND_GET_MODULE(ibase) #endif /* True globals, no need for thread safety */ -int le_blob, le_link, le_plink, le_result, le_query, le_trans, le_event, le_service; +int le_link, le_plink, le_trans; ZEND_DECLARE_MODULE_GLOBALS(ibase) @@ -238,28 +221,6 @@ typedef struct { char *tpb_ptr; } ISC_TEB; -typedef struct { - unsigned short vary_length; - char vary_string[1]; -} IBVARY; - -/* sql variables union - * used for convert and binding input variables - */ -typedef struct { - union { - short sval; - float fval; - ISC_LONG lval; - ISC_QUAD qval; -#ifdef SQL_TIMESTAMP - ISC_TIMESTAMP tsval; - ISC_DATE dtval; - ISC_TIME tmval; -#endif - } val; - short sqlind; -} BIND_BUF; /* }}} */ /* Fill ib_link and trans with the correct database link and transaction. */ @@ -293,71 +254,6 @@ void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */ /* destructors ---------------------- */ -static void _php_ibase_free_xsqlda(XSQLDA *sqlda) /* {{{ */ -{ - int i; - XSQLVAR *var; - - IBDEBUG("Free XSQLDA?"); - if (sqlda) { - IBDEBUG("Freeing XSQLDA..."); - var = sqlda->sqlvar; - for (i = 0; i < sqlda->sqld; i++, var++) { - efree(var->sqldata); - if (var->sqlind) { - efree(var->sqlind); - } - } - efree(sqlda); - } -} -/* }}} */ - -static void _php_ibase_free_event(ibase_event *event TSRMLS_DC) /* {{{ */ -{ - unsigned short i; - - event->state = DEAD; - - if (event->link != NULL) { - ibase_event **node; - - if (event->link->handle != NULL && - isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) { - _php_ibase_error(TSRMLS_C); - } - - /* delete this event from the link struct */ - for (node = &event->link->event_head; *node != event; node = &(*node)->event_next); - *node = event->event_next; - } - - if (event->callback) { - zval_dtor(event->callback); - FREE_ZVAL(event->callback); - event->callback = NULL; - - _php_ibase_event_free(event->event_buffer,event->result_buffer); - - for (i = 0; i < event->event_count; ++i) { - efree(event->events[i]); - } - efree(event->events); - } -} -/* }}} */ - -static void _php_ibase_free_event_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - ibase_event *e = (ibase_event *) rsrc->ptr; - IBDEBUG("Cleaning up event resource"); - - _php_ibase_free_event(e TSRMLS_CC); - - efree(e); -} -/* }}} */ - static void _php_ibase_commit_link(ibase_db_link *link TSRMLS_DC) /* {{{ */ { unsigned short i = 0, j; @@ -444,80 +340,6 @@ static void _php_ibase_close_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ } /* }}} */ -static void _php_ibase_free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - ibase_result *ib_result = (ibase_result *) rsrc->ptr; - - IBDEBUG("Freeing result by dtor..."); - if (ib_result) { - _php_ibase_free_xsqlda(ib_result->out_sqlda); - if (ib_result->stmt && ib_result->type != EXECUTE_RESULT) { - IBDEBUG("Dropping statement handle (free_result dtor)..."); - isc_dsql_free_statement(IB_STATUS, &ib_result->stmt, DSQL_drop); - } - efree(ib_result); - } -} -/* }}} */ - -static void _php_ibase_free_query(ibase_query *ib_query TSRMLS_DC) /* {{{ */ -{ - IBDEBUG("Freeing query..."); - - if (ib_query->in_sqlda) { - efree(ib_query->in_sqlda); - } - if (ib_query->out_sqlda) { - efree(ib_query->out_sqlda); - } - if (ib_query->stmt) { - IBDEBUG("Dropping statement handle (free_query)..."); - if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_drop)) { - _php_ibase_error(TSRMLS_C); - } - } - if (ib_query->in_array) { - efree(ib_query->in_array); - } - if (ib_query->out_array) { - efree(ib_query->out_array); - } - if (ib_query->query) { - efree(ib_query->query); - } -} -/* }}} */ - -static void php_ibase_free_query_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - ibase_query *ib_query = (ibase_query *)rsrc->ptr; - - if (ib_query != NULL) { - IBDEBUG("Preparing to free query by dtor..."); - - _php_ibase_free_query(ib_query TSRMLS_CC); - if (ib_query->statement_type != isc_info_sql_stmt_exec_procedure) { - zend_list_delete(ib_query->result_res_id); - } - efree(ib_query); - } -} -/* }}} */ - -static void _php_ibase_free_blob(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - ibase_blob *ib_blob = (ibase_blob *)rsrc->ptr; - - if (ib_blob->bl_handle != NULL) { /* blob open*/ - if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) { - _php_ibase_module_error("You can lose data. Close any blob after reading from or " - "writing to it. Use ibase_blob_close() before calling ibase_close()" TSRMLS_CC); - } - } - efree(ib_blob); -} -/* }}} */ - static void _php_ibase_free_trans(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ { ibase_trans *trans = (ibase_trans *)rsrc->ptr; @@ -549,29 +371,6 @@ static void _php_ibase_free_trans(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ * } /* }}} */ -#if HAVE_IBASE6_API -static void _php_ibase_free_service(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ -{ - ibase_service *sv = (ibase_service *) rsrc->ptr; - - IBDEBUG("Cleaning up service manager resource"); - - if (isc_service_detach(IB_STATUS, &sv->handle)) { - _php_ibase_error(TSRMLS_C); - } - - if (sv->hostname) { - efree(sv->hostname); - } - if (sv->username) { - efree(sv->username); - } - - efree(sv); -} -/* }}} */ -#endif - /* {{{ startup, shutdown and info functions */ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("ibase.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_ibase_globals, ibase_globals) @@ -601,16 +400,9 @@ PHP_MINIT_FUNCTION(ibase) REGISTER_INI_ENTRIES(); - le_result = zend_register_list_destructors_ex(_php_ibase_free_result, NULL, "interbase result", module_number); - le_query = zend_register_list_destructors_ex(php_ibase_free_query_rsrc, NULL, "interbase query", module_number); - le_blob = zend_register_list_destructors_ex(_php_ibase_free_blob, NULL, "interbase blob", module_number); le_link = zend_register_list_destructors_ex(_php_ibase_close_link, NULL, "interbase link", module_number); le_plink = zend_register_list_destructors_ex(php_ibase_commit_link_rsrc, _php_ibase_close_plink, "interbase link persistent", module_number); le_trans = zend_register_list_destructors_ex(_php_ibase_free_trans, NULL, "interbase transaction", module_number); - le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, "interbase event", module_number); -#if HAVE_IBASE6_API - le_service = zend_register_list_destructors_ex(_php_ibase_free_service, NULL, "interbase service manager handle", module_number); -#endif REGISTER_LONG_CONSTANT("IBASE_DEFAULT", PHP_IBASE_DEFAULT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IBASE_TEXT", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT); /* deprecated, for BC only */ @@ -620,6 +412,7 @@ PHP_MINIT_FUNCTION(ibase) REGISTER_LONG_CONSTANT("IBASE_TIMESTAMP", PHP_IBASE_TIMESTAMP, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IBASE_DATE", PHP_IBASE_DATE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IBASE_TIME", PHP_IBASE_TIME, CONST_PERSISTENT); + /* transactions */ REGISTER_LONG_CONSTANT("IBASE_WRITE", PHP_IBASE_WRITE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IBASE_READ", PHP_IBASE_READ, CONST_PERSISTENT); @@ -630,65 +423,12 @@ PHP_MINIT_FUNCTION(ibase) REGISTER_LONG_CONSTANT("IBASE_REC_NO_VERSION", PHP_IBASE_REC_NO_VERSION, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IBASE_NOWAIT", PHP_IBASE_NOWAIT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IBASE_WAIT", PHP_IBASE_WAIT, CONST_PERSISTENT); -#if HAVE_IBASE6_API - /* backup options */ - REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_CHECKSUMS", isc_spb_bkp_ignore_checksums, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_LIMBO", isc_spb_bkp_ignore_limbo, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_BKP_METADATA_ONLY", isc_spb_bkp_metadata_only, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_BKP_NO_GARBAGE_COLLECT", isc_spb_bkp_no_garbage_collect, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_BKP_OLD_DESCRIPTIONS", isc_spb_bkp_old_descriptions, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_BKP_NON_TRANSPORTABLE", isc_spb_bkp_non_transportable, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_BKP_CONVERT", isc_spb_bkp_convert, CONST_PERSISTENT); - /* restore options */ - REGISTER_LONG_CONSTANT("IBASE_RES_DEACTIVATE_IDX", isc_spb_res_deactivate_idx, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RES_NO_SHADOW", isc_spb_res_no_shadow, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RES_NO_VALIDITY", isc_spb_res_no_validity, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RES_ONE_AT_A_TIME", isc_spb_res_one_at_a_time, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RES_REPLACE", isc_spb_res_replace, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RES_CREATE", isc_spb_res_create, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RES_USE_ALL_SPACE", isc_spb_res_use_all_space, CONST_PERSISTENT); - /* manage options */ - REGISTER_LONG_CONSTANT("IBASE_PRP_PAGE_BUFFERS", isc_spb_prp_page_buffers, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_SWEEP_INTERVAL", isc_spb_prp_sweep_interval, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_SHUTDOWN_DB", isc_spb_prp_shutdown_db, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_TRANSACTIONS", isc_spb_prp_deny_new_transactions, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_ATTACHMENTS", isc_spb_prp_deny_new_attachments, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_RESERVE_SPACE", isc_spb_prp_reserve_space, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_RES_USE_FULL", isc_spb_prp_res_use_full, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_RES", isc_spb_prp_res, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_WRITE_MODE", isc_spb_prp_write_mode, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_WM_ASYNC", isc_spb_prp_wm_async, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_WM_SYNC", isc_spb_prp_wm_sync, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_ACCESS_MODE", isc_spb_prp_access_mode, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READONLY", isc_spb_prp_am_readonly, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READWRITE", isc_spb_prp_am_readwrite, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_SET_SQL_DIALECT", isc_spb_prp_set_sql_dialect, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_ACTIVATE", isc_spb_prp_activate, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_PRP_DB_ONLINE", isc_spb_prp_db_online, CONST_PERSISTENT); - /* repair options */ - REGISTER_LONG_CONSTANT("IBASE_RPR_CHECK_DB", isc_spb_rpr_check_db, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RPR_IGNORE_CHECKSUM", isc_spb_rpr_ignore_checksum, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RPR_KILL_SHADOWS", isc_spb_rpr_kill_shadows, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RPR_MEND_DB", isc_spb_rpr_mend_db, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RPR_VALIDATE_DB", isc_spb_rpr_validate_db, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RPR_FULL", isc_spb_rpr_full, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_RPR_SWEEP_DB", isc_spb_rpr_sweep_db, CONST_PERSISTENT); - /* db info arguments */ - REGISTER_LONG_CONSTANT("IBASE_STS_DATA_PAGES", isc_spb_sts_data_pages, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_STS_DB_LOG", isc_spb_sts_db_log, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_STS_HDR_PAGES", isc_spb_sts_hdr_pages, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_STS_IDX_PAGES", isc_spb_sts_idx_pages, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_STS_SYS_RELATIONS", isc_spb_sts_sys_relations, CONST_PERSISTENT); - /* server info arguments */ - REGISTER_LONG_CONSTANT("IBASE_SVC_SERVER_VERSION", isc_info_svc_server_version, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_IMPLEMENTATION", isc_info_svc_implementation, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV", isc_info_svc_get_env, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_LOCK", isc_info_svc_get_env_lock, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_MSG", isc_info_svc_get_env_msg, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_USER_DBPATH", isc_info_svc_user_dbpath, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_SVR_DB_INFO", isc_info_svc_svr_db_info, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IBASE_SVC_GET_USERS", isc_info_svc_get_users, CONST_PERSISTENT); -#endif + + php_ibase_query_minit(INIT_FUNC_ARGS_PASSTHRU); + php_ibase_blobs_minit(INIT_FUNC_ARGS_PASSTHRU); + php_ibase_events_minit(INIT_FUNC_ARGS_PASSTHRU); + php_ibase_service_minit(INIT_FUNC_ARGS_PASSTHRU); + return SUCCESS; } @@ -1096,907 +836,6 @@ PHP_FUNCTION(ibase_drop_db) } /* }}} */ -static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ */ - isc_db_handle link, isc_tr_handle trans, unsigned short *array_cnt TSRMLS_DC) -{ - unsigned short i, n; - ibase_array *ar; - - /* first check if we have any arrays at all */ - for (i = *array_cnt = 0; i < sqlda->sqld; ++i) { - if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_ARRAY) { - ++*array_cnt; - } - } - if (! *array_cnt) return SUCCESS; - - ar = safe_emalloc(sizeof(ibase_array), *array_cnt, 0); - - for (i = n = 0; i < sqlda->sqld; ++i) { - unsigned short dim; - unsigned long ar_size = 1; - XSQLVAR *var = &sqlda->sqlvar[i]; - - if ((var->sqltype & ~1) == SQL_ARRAY) { - ibase_array *a = &ar[n++]; - ISC_ARRAY_DESC *ar_desc = &a->ar_desc; - - if (isc_array_lookup_bounds(IB_STATUS, &link, &trans, var->relname, - var->sqlname, ar_desc)) { - _php_ibase_error(TSRMLS_C); - efree(ar); - return FAILURE; - } - - switch (ar_desc->array_desc_dtype) { - case blr_text: - case blr_text2: - a->el_type = SQL_TEXT; - a->el_size = ar_desc->array_desc_length; - break; - case blr_short: - a->el_type = SQL_SHORT; - a->el_size = sizeof(short); - break; - case blr_long: - a->el_type = SQL_LONG; - a->el_size = sizeof(ISC_LONG); - break; - case blr_float: - a->el_type = SQL_FLOAT; - a->el_size = sizeof(float); - break; - case blr_double: - a->el_type = SQL_DOUBLE; - a->el_size = sizeof(double); - break; -#ifdef blr_int64 - case blr_int64: - a->el_type = SQL_INT64; - a->el_size = sizeof(ISC_INT64); - break; -#endif -#ifndef blr_timestamp - case blr_date: - a->el_type = SQL_DATE; - a->el_size = sizeof(ISC_QUAD); - break; -#else - case blr_timestamp: - a->el_type = SQL_TIMESTAMP; - a->el_size = sizeof(ISC_TIMESTAMP); - break; - case blr_sql_date: - a->el_type = SQL_TYPE_DATE; - a->el_size = sizeof(ISC_DATE); - break; - case blr_sql_time: - a->el_type = SQL_TYPE_TIME; - a->el_size = sizeof(ISC_TIME); - break; -#endif - case blr_varying: - case blr_varying2: - /** - * IB has a strange way of handling VARCHAR arrays. It doesn't store - * the length in the first short, as with VARCHAR fields. It does, - * however, expect the extra short to be allocated for each element. - */ - a->el_type = SQL_TEXT; - a->el_size = ar_desc->array_desc_length + sizeof(short); - break; - case blr_quad: - case blr_blob_id: - case blr_cstring: - case blr_cstring2: - /** - * These types are mentioned as array types in the manual, but I - * wouldn't know how to create an array field with any of these - * types. I assume these types are not applicable to arrays, and - * were mentioned erroneously. - */ - default: - _php_ibase_module_error("Unsupported array type %d in relation '%s' column '%s'" - TSRMLS_CC, ar_desc->array_desc_dtype, var->relname, var->sqlname); - efree(ar); - return FAILURE; - } /* switch array_desc_type */ - - /* calculate elements count */ - for (dim = 0; dim < ar_desc->array_desc_dimensions; dim++) { - ar_size *= 1 + ar_desc->array_desc_bounds[dim].array_bound_upper - -ar_desc->array_desc_bounds[dim].array_bound_lower; - } - a->ar_size = a->el_size * ar_size; - } /* if SQL_ARRAY */ - } /* for column */ - *ib_arrayp = ar; - return SUCCESS; -} -/* }}} */ - -/* allocate and prepare query */ -static int _php_ibase_alloc_query(ibase_query *ib_query, ibase_db_link *link, /* {{{ */ - ibase_trans *trans, char *query, unsigned short dialect, int trans_res_id TSRMLS_DC) -{ - static char info_type[] = {isc_info_sql_stmt_type}; - char result[8]; - - ib_query->link = link; - ib_query->trans = trans; - ib_query->result_res_id = 0; - ib_query->stmt = NULL; - ib_query->in_array = NULL; - ib_query->out_array = NULL; - ib_query->dialect = dialect; - ib_query->query = estrdup(query); - ib_query->trans_res_id = trans_res_id; - - if (isc_dsql_allocate_statement(IB_STATUS, &link->handle, &ib_query->stmt)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_alloc_query_error; - } - - ib_query->out_sqlda = (XSQLDA *) emalloc(XSQLDA_LENGTH(1)); - ib_query->out_sqlda->sqln = 1; - ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION; - - if (isc_dsql_prepare(IB_STATUS, &ib_query->trans->handle, &ib_query->stmt, - 0, query, dialect, ib_query->out_sqlda)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_alloc_query_error; - } - - /* find out what kind of statement was prepared */ - if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_type), - info_type, sizeof(result), result)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_alloc_query_error; - } - ib_query->statement_type = result[3]; - - /* not enough output variables ? */ - if (ib_query->out_sqlda->sqld > ib_query->out_sqlda->sqln) { - ib_query->out_sqlda = erealloc(ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld)); - ib_query->out_sqlda->sqln = ib_query->out_sqlda->sqld; - ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION; - if (isc_dsql_describe(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->out_sqlda)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_alloc_query_error; - } - } - - /* maybe have input placeholders? */ - ib_query->in_sqlda = emalloc(XSQLDA_LENGTH(1)); - ib_query->in_sqlda->sqln = 1; - ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION; - if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_alloc_query_error; - } - - /* not enough input variables ? */ - if (ib_query->in_sqlda->sqln < ib_query->in_sqlda->sqld) { - ib_query->in_sqlda = erealloc(ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld)); - ib_query->in_sqlda->sqln = ib_query->in_sqlda->sqld; - ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION; - - if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, - SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_alloc_query_error; - } - } - - /* no, haven't placeholders at all */ - if (ib_query->in_sqlda->sqld == 0) { - efree(ib_query->in_sqlda); - ib_query->in_sqlda = NULL; - } else if (FAILURE == _php_ibase_alloc_array(&ib_query->in_array, ib_query->in_sqlda, - link->handle, trans->handle, &ib_query->in_array_cnt TSRMLS_CC)) { - goto _php_ibase_alloc_query_error; - } - - if (ib_query->out_sqlda->sqld == 0) { - efree(ib_query->out_sqlda); - ib_query->out_sqlda = NULL; - } else if (FAILURE == _php_ibase_alloc_array(&ib_query->out_array, ib_query->out_sqlda, - link->handle, trans->handle, &ib_query->out_array_cnt TSRMLS_CC)) { - goto _php_ibase_alloc_query_error; - } - - return SUCCESS; - -_php_ibase_alloc_query_error: - - if (ib_query->out_sqlda) { - efree(ib_query->out_sqlda); - } - if (ib_query->in_sqlda) { - efree(ib_query->in_sqlda); - } - if (ib_query->out_array) { - efree(ib_query->out_array); - } - if (ib_query->query) { - efree(ib_query->query); - } - return FAILURE; -} -/* }}} */ - -static int _php_ibase_bind_array(zval *val, char *buf, unsigned long buf_size, /* {{{ */ - ibase_array *array, int dim TSRMLS_DC) -{ - zval null_val, *pnull_val = &null_val; - int u_bound = array->ar_desc.array_desc_bounds[dim].array_bound_upper, - l_bound = array->ar_desc.array_desc_bounds[dim].array_bound_lower, - dim_len = 1 + u_bound - l_bound; - - ZVAL_NULL(pnull_val); - - if (dim < array->ar_desc.array_desc_dimensions) { - unsigned long slice_size = buf_size / dim_len; - unsigned short i; - zval **subval = &val; - - if (Z_TYPE_P(val) == IS_ARRAY) { - zend_hash_internal_pointer_reset(Z_ARRVAL_P(val)); - } - - for (i = 0; i < dim_len; ++i) { - - if (Z_TYPE_P(val) == IS_ARRAY && - zend_hash_get_current_data(Z_ARRVAL_P(val), (void *) &subval) == FAILURE) - { - subval = &pnull_val; - } - - if (_php_ibase_bind_array(*subval, buf, slice_size, array, dim+1 TSRMLS_CC) == FAILURE) - { - return FAILURE; - } - buf += slice_size; - - if (Z_TYPE_P(val) == IS_ARRAY) { - zend_hash_move_forward(Z_ARRVAL_P(val)); - } - } - - if (Z_TYPE_P(val) == IS_ARRAY) { - zend_hash_internal_pointer_reset(Z_ARRVAL_P(val)); - } - - } else { - /* expect a single value */ - if (Z_TYPE_P(val) == IS_NULL) { - memset(buf, 0, buf_size); - } else if (array->ar_desc.array_desc_scale < 0) { - - /* no coercion for array types */ - double l; - - convert_to_double(val); - - if (Z_DVAL_P(val) > 0) { - l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) + .5; - } else { - l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) - .5; - } - - switch (array->el_type) { - case SQL_SHORT: - if (l > SHRT_MAX || l < SHRT_MIN) { - _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); - return FAILURE; - } - *(short*) buf = (short) l; - break; - case SQL_LONG: - if (l > ISC_LONG_MAX || l < ISC_LONG_MIN) { - _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); - return FAILURE; - } - *(ISC_LONG*) buf = (ISC_LONG) l; - break; -#ifdef SQL_INT64 - case SQL_INT64: - { - long double l; - - convert_to_string(val); - - if (!sscanf(Z_STRVAL_P(val), "%Lf", &l)) { - _php_ibase_module_error("Cannot convert '%s' to long double" - TSRMLS_CC, Z_STRVAL_P(val)); - return FAILURE; - } - - if (l > 0) { - *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10, - -array->ar_desc.array_desc_scale) + .5); - } else { - *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10, - -array->ar_desc.array_desc_scale) - .5); - } - } - break; -#endif - } - } else { - struct tm t = { 0, 0, 0, 0, 0, 0 }; - - switch (array->el_type) { - unsigned short n; - - case SQL_SHORT: - convert_to_long(val); - if (Z_LVAL_P(val) > SHRT_MAX || Z_LVAL_P(val) < SHRT_MIN) { - _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); - return FAILURE; - } - *(short *) buf = (short) Z_LVAL_P(val); - break; - case SQL_LONG: - convert_to_long(val); -#if (SIZEOF_LONG > 4) - if (Z_LVAL_P(val) > ISC_LONG_MAX || Z_LVAL_P(val) < ISC_LONG_MIN) { - _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC); - return FAILURE; - } -#endif - *(ISC_LONG *) buf = (ISC_LONG) Z_LVAL_P(val); - break; -#ifdef SQL_INT64 - case SQL_INT64: -#if (SIZEOF_LONG >= 8) - convert_to_long(val); - *(long *) buf = Z_LVAL_P(val); -#else - { - ISC_INT64 l; - - convert_to_string(val); - if (!sscanf(Z_STRVAL_P(val), "%" LL_MASK "d", &l)) { - _php_ibase_module_error("Cannot convert '%s' to long integer" - TSRMLS_CC, Z_STRVAL_P(val)); - return FAILURE; - } else { - *(ISC_INT64 *) buf = l; - } - } -#endif - break; -#endif - case SQL_FLOAT: - convert_to_double(val); - *(float*) buf = (float) Z_DVAL_P(val); - break; - case SQL_DOUBLE: - convert_to_double(val); - *(double*) buf = Z_DVAL_P(val); - break; -#ifndef SQL_TIMESTAMP - case SQL_DATE: -#else - case SQL_TIMESTAMP: -#endif - convert_to_string(val); -#ifdef HAVE_STRPTIME - strptime(Z_STRVAL_P(val), IBG(timestampformat), &t); -#else - n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d", - &t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec); - - if (n != 3 && n != 6) { - _php_ibase_module_error("Invalid date/time format (expected 3 or 6 fields, got %d." - " Use format 'm/d/Y H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val)); - return FAILURE; - } - t.tm_year -= 1900; - t.tm_mon--; -#endif -#ifndef SQL_TIMESTAMP - isc_encode_date(&t, (ISC_QUAD *) buf); - break; -#else - isc_encode_timestamp(&t, (ISC_TIMESTAMP * ) buf); - break; - case SQL_TYPE_DATE: - convert_to_string(val); -#ifdef HAVE_STRPTIME - strptime(Z_STRVAL_P(val), IBG(dateformat), &t); -#else - n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d", &t.tm_mon, &t.tm_mday, &t.tm_year); - - if (n != 3) { - _php_ibase_module_error("Invalid date format (expected 3 fields, got %d. " - "Use format 'm/d/Y' You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val)); - return FAILURE; - } - t.tm_year -= 1900; - t.tm_mon--; -#endif - isc_encode_sql_date(&t, (ISC_DATE *) buf); - break; - case SQL_TYPE_TIME: - convert_to_string(val); -#ifdef HAVE_STRPTIME - strptime(Z_STRVAL_P(val), IBG(timeformat), &t); -#else - n = sscanf(Z_STRVAL_P(val), "%d%*[:]%d%*[:]%d", &t.tm_hour, &t.tm_min, &t.tm_sec); - - if (n != 3) { - _php_ibase_module_error("Invalid time format (expected 3 fields, got %d. " - "Use format 'H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val)); - return FAILURE; - } -#endif - isc_encode_sql_time(&t, (ISC_TIME *) buf); - break; -#endif - default: - convert_to_string(val); - strncpy(buf, Z_STRVAL_P(val), array->el_size); - buf[array->el_size-1] = '\0'; - } - } - } - return SUCCESS; -} -/* }}} */ - -static int _php_ibase_bind(XSQLDA *sqlda, zval **b_vars, BIND_BUF *buf, /* {{{ */ - ibase_query *ib_query TSRMLS_DC) -{ - int i, array_cnt = 0, rv = SUCCESS; - - for (i = 0; i < sqlda->sqld; ++i) { /* bound vars */ - - zval *b_var = b_vars[i]; - XSQLVAR *var = &sqlda->sqlvar[i]; - - var->sqlind = &buf[i].sqlind; - - if (Z_TYPE_P(b_var) == IS_NULL) { - if ((var->sqltype & 1) != 1) { - _php_ibase_module_error("Parameter %d must have a value" TSRMLS_CC, i+1); - rv = FAILURE; - } - buf[i].sqlind = -1; - if ((var->sqltype & ~1) == SQL_ARRAY) ++array_cnt; - } else { - buf[i].sqlind = 0; - - if (var->sqlscale < 0) { - /* - DECIMAL or NUMERIC field are stored internally as scaled integers. - Coerce it to string and let InterBase's internal routines handle it. - */ - var->sqltype = SQL_TEXT; - } - - var->sqldata = (void*)&buf[i]; - - switch (var->sqltype & ~1) { - struct tm t; - - case SQL_SHORT: - convert_to_long(b_var); - if (Z_LVAL_P(b_var) > SHRT_MAX || Z_LVAL_P(b_var) < SHRT_MIN) { - _php_ibase_module_error("Parameter %d exceeds field width" TSRMLS_CC, i+1); - rv = FAILURE; - break; - } - buf[i].val.sval = (short) Z_LVAL_P(b_var); - break; - case SQL_LONG: - convert_to_long(b_var); -#if (SIZEOF_LONG > 4) - /* ISC_LONG is always 32-bit */ - if (Z_LVAL_P(b_var) > ISC_LONG_MAX || Z_LVAL_P(b_var) < ISC_LONG_MIN) { - _php_ibase_module_error("Parameter %d exceeds field width" TSRMLS_CC, i+1); - rv = FAILURE; - break; - } -#endif - buf[i].val.lval = (ISC_LONG) Z_LVAL_P(b_var); - break; -#if defined(SQL_INT64) && (SIZEOF_LONG == 8) - case SQL_INT64: - convert_to_long(b_var); - var->sqldata = (void *) &Z_LVAL_P(b_var); - break; -#endif - case SQL_FLOAT: - convert_to_double(b_var); - buf[i].val.fval = (float) Z_DVAL_P(b_var); - break; - case SQL_DOUBLE: - convert_to_double(b_var); - var->sqldata = (void *) &Z_DVAL_P(b_var); - break; - - case SQL_DATE: /* == SQL_TIMESTAMP: */ -#ifdef SQL_TIMESTAMP - case SQL_TYPE_DATE: - case SQL_TYPE_TIME: -#endif - if (Z_TYPE_P(b_var) == IS_LONG) { - /* insert timestamp directly */ - t = *gmtime(&Z_LVAL_P(b_var)); - } else { -#ifndef HAVE_STRPTIME -#ifndef SQL_TIMESTAMP - int n; - - t.tm_year = t.tm_mon = t.tm_mday = t.tm_hour = t.tm_min = t.tm_sec = 0; - - n = sscanf(Z_STRVAL_P(b_var), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d", - &t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec); - - if (n != 3 && n != 6) { - _php_ibase_module_error("Parameter %d: invalid date/time format " - "(expected 3 or 6 fields, got %d. Use format m/d/Y H:i:s. You gave '%s')" - TSRMLS_CC, i+1, n, Z_STRVAL_P(b_var)); - rv = FAILURE; - break; - } - t.tm_year -= 1900; - t.tm_mon--; -#else - goto php_ibase_bind_default; /* let IB string handling take over */ -#endif -#else - convert_to_string(b_var); - - switch (var->sqltype & ~1) { - default: /* == case SQL_TIMESTAMP/SQL_DATE: */ - strptime(Z_STRVAL_P(b_var), IBG(timestampformat), &t); - break; - case SQL_TYPE_DATE: - strptime(Z_STRVAL_P(b_var), IBG(dateformat), &t); - break; - case SQL_TYPE_TIME: - strptime(Z_STRVAL_P(b_var), IBG(timeformat), &t); - break; - } -#endif - } - -#ifndef SQL_TIMESTAMP - isc_encode_date(&t, &buf[i].val.qval); -#else - switch (var->sqltype & ~1) { - default: /* == case SQL_TIMESTAMP */ - isc_encode_timestamp(&t, &buf[i].val.tsval); - break; - case SQL_TYPE_DATE: - isc_encode_sql_date(&t, &buf[i].val.dtval); - break; - case SQL_TYPE_TIME: - isc_encode_sql_time(&t, &buf[i].val.tmval); - break; -#endif - } - break; - case SQL_BLOB: - - convert_to_string(b_var); - - if (Z_STRLEN_P(b_var) != BLOB_ID_LEN || - !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) { - - ibase_blob ib_blob = { NULL, BLOB_INPUT }; - - if (isc_create_blob(IB_STATUS, &ib_query->link->handle, - &ib_query->trans->handle, &ib_blob.bl_handle, &ib_blob.bl_qd)) { - _php_ibase_error(TSRMLS_C); - return FAILURE; - } - - if (_php_ibase_blob_add(&b_var, &ib_blob TSRMLS_CC) != SUCCESS) { - return FAILURE; - } - - if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { - _php_ibase_error(TSRMLS_C); - return FAILURE; - } - buf[i].val.qval = ib_blob.bl_qd; - } - break; - case SQL_ARRAY: - if (Z_TYPE_P(b_var) != IS_ARRAY) { - convert_to_string(b_var); - - if (Z_STRLEN_P(b_var) != BLOB_ID_LEN || - !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) { - - _php_ibase_module_error("Parameter %d: invalid array ID" TSRMLS_CC,i+1); - rv = FAILURE; - } - } else { - /* convert the array data into something IB can understand */ - ibase_array *ar = &ib_query->in_array[array_cnt++]; - void *array_data = emalloc(ar->ar_size); - ISC_QUAD array_id = { 0, 0 }; - - if (FAILURE == _php_ibase_bind_array(b_var, array_data, ar->ar_size, - ar, 0 TSRMLS_CC)) { - _php_ibase_module_error("Parameter %d: failed to bind array argument" - TSRMLS_CC,i+1); - efree(array_data); - rv = FAILURE; - break; - } - - if (isc_array_put_slice(IB_STATUS, &ib_query->link->handle, &ib_query->trans->handle, - &array_id, &ar->ar_desc, array_data, &ar->ar_size)) { - _php_ibase_error(TSRMLS_C); - efree(array_data); - return FAILURE; - } - buf[i].val.qval = array_id; - efree(array_data); - } - break; - default: -php_ibase_bind_default: - convert_to_string(b_var); - var->sqldata = Z_STRVAL_P(b_var); - var->sqllen = Z_STRLEN_P(b_var); - var->sqltype = SQL_TEXT; - } /* switch */ - } /* if */ - } /* for */ - return rv; -} -/* }}} */ - -static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */ -{ - int i; - - for (i = 0; i < sqlda->sqld; i++) { - XSQLVAR *var = &sqlda->sqlvar[i]; - - switch (var->sqltype & ~1) { - case SQL_TEXT: - var->sqldata = safe_emalloc(sizeof(char), var->sqllen, 0); - break; - case SQL_VARYING: - var->sqldata = safe_emalloc(sizeof(char), var->sqllen + sizeof(short), 0); - break; - case SQL_SHORT: - var->sqldata = emalloc(sizeof(short)); - break; - case SQL_LONG: - var->sqldata = emalloc(sizeof(ISC_LONG)); - break; - case SQL_FLOAT: - var->sqldata = emalloc(sizeof(float)); - break; - case SQL_DOUBLE: - var->sqldata = emalloc(sizeof(double)); - break; -#ifdef SQL_INT64 - case SQL_INT64: - var->sqldata = emalloc(sizeof(ISC_INT64)); - break; -#endif -#ifdef SQL_TIMESTAMP - case SQL_TIMESTAMP: - var->sqldata = emalloc(sizeof(ISC_TIMESTAMP)); - break; - case SQL_TYPE_DATE: - var->sqldata = emalloc(sizeof(ISC_DATE)); - break; - case SQL_TYPE_TIME: - var->sqldata = emalloc(sizeof(ISC_TIME)); - break; -#else - case SQL_DATE: -#endif - case SQL_BLOB: - case SQL_ARRAY: - var->sqldata = emalloc(sizeof(ISC_QUAD)); - break; - } /* switch */ - - if (var->sqltype & 1) { /* sql NULL flag */ - var->sqlind = emalloc(sizeof(short)); - } else { - var->sqlind = NULL; - } - } /* for */ -} -/* }}} */ - -static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resultp, /* {{{ */ - ibase_query *ib_query, int argc, zval **args) -{ - XSQLDA *in_sqlda = NULL, *out_sqlda = NULL; - BIND_BUF *bind_buf = NULL; - int rv = FAILURE; - static char info_count[] = { isc_info_sql_records }; - char result[64]; - ISC_STATUS isc_result; - - RESET_ERRMSG; - - if (argc > 0 && args != NULL) { - SEPARATE_ZVAL(args); - } - - switch (ib_query->statement_type) { - isc_tr_handle tr; - ibase_tr_list **l; - ibase_trans *trans; - - case isc_info_sql_stmt_start_trans: - - /* a SET TRANSACTION statement should be executed with a NULL trans handle */ - tr = NULL; - - if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, &tr, 0, - ib_query->query, ib_query->dialect, NULL)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_exec_error; - } - - trans = (ibase_trans *) emalloc(sizeof(ibase_trans)); - trans->handle = tr; - trans->link_cnt = 1; - trans->affected_rows = 0; - trans->db_link[0] = ib_query->link; - - if (ib_query->link->tr_list == NULL) { - ib_query->link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); - ib_query->link->tr_list->trans = NULL; - ib_query->link->tr_list->next = NULL; - } - - /* link the transaction into the connection-transaction list */ - for (l = &ib_query->link->tr_list; *l != NULL; l = &(*l)->next); - *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); - (*l)->trans = trans; - (*l)->next = NULL; - - ZEND_REGISTER_RESOURCE(return_value, trans, le_trans); - - return SUCCESS; - - case isc_info_sql_stmt_commit: - case isc_info_sql_stmt_rollback: - - if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, - &ib_query->trans->handle, 0, ib_query->query, ib_query->dialect, NULL)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_exec_error; - } - - if (ib_query->trans->handle == NULL && ib_query->trans_res_id != 0) { - /* transaction was released by the query and was a registered resource, - so we have to release it */ - zend_list_delete(ib_query->trans_res_id); - } - return SUCCESS; - - default: - RETVAL_TRUE; - } - - /* allocate sqlda and output buffers */ - if (ib_query->out_sqlda) { /* output variables in select, select for update */ - ibase_result *res; - - IBDEBUG("Query wants XSQLDA for output"); - res = emalloc(sizeof(ibase_result)+sizeof(ibase_array)*max(0,ib_query->out_array_cnt-1)); - res->link = ib_query->link; - res->trans = ib_query->trans; - res->stmt = ib_query->stmt; - res->statement_type = ib_query->statement_type; - res->has_more_rows = 1; - - out_sqlda = res->out_sqlda = emalloc(XSQLDA_LENGTH(ib_query->out_sqlda->sqld)); - memcpy(out_sqlda, ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld)); - _php_ibase_alloc_xsqlda(out_sqlda); - - if (ib_query->out_array) { - memcpy(&res->out_array, ib_query->out_array, sizeof(ibase_array)*ib_query->out_array_cnt); - } - *ib_resultp = res; - } - - if (ib_query->in_sqlda) { /* has placeholders */ - IBDEBUG("Query wants XSQLDA for input"); - if (ib_query->in_sqlda->sqld != argc) { - _php_ibase_module_error("Placeholders (%d) and variables (%d) mismatch" - TSRMLS_CC, ib_query->in_sqlda->sqld, argc); - goto _php_ibase_exec_error; - } - in_sqlda = emalloc(XSQLDA_LENGTH(ib_query->in_sqlda->sqld)); - memcpy(in_sqlda, ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld)); - bind_buf = safe_emalloc(sizeof(BIND_BUF), ib_query->in_sqlda->sqld, 0); - if (_php_ibase_bind(in_sqlda, args, bind_buf, ib_query TSRMLS_CC) == FAILURE) { - IBDEBUG("Could not bind input XSQLDA"); - goto _php_ibase_exec_error; - } - } - - if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) { - isc_result = isc_dsql_execute2(IB_STATUS, &ib_query->trans->handle, - &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda, out_sqlda); - } else { - isc_result = isc_dsql_execute(IB_STATUS, &ib_query->trans->handle, - &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda); - } - if (isc_result) { - IBDEBUG("Could not execute query"); - _php_ibase_error(TSRMLS_C); - goto _php_ibase_exec_error; - } - ib_query->trans->affected_rows = 0; - - switch (ib_query->statement_type) { - - unsigned long affected_rows; - - case isc_info_sql_stmt_insert: - case isc_info_sql_stmt_update: - case isc_info_sql_stmt_delete: - case isc_info_sql_stmt_exec_procedure: - - if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_count), - info_count, sizeof(result), result)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_exec_error; - } - - affected_rows = 0; - - if (result[0] == isc_info_sql_records) { - unsigned i = 3, result_size = isc_vax_integer(&result[1],2); - - while (result[i] != isc_info_end && i < result_size) { - short len = (short)isc_vax_integer(&result[i+1],2); - if (result[i] != isc_info_req_select_count) { - affected_rows += isc_vax_integer(&result[i+3],len); - } - i += len+3; - } - } - if (affected_rows > 0) { - ib_query->trans->affected_rows = affected_rows; - RETVAL_LONG(affected_rows); - } - } - - rv = SUCCESS; - -_php_ibase_exec_error: - - if (in_sqlda) { - efree(in_sqlda); - } - if (bind_buf) - efree(bind_buf); - - if (rv == FAILURE) { - if (*ib_resultp) { - efree(*ib_resultp); - *ib_resultp = NULL; - } - if (out_sqlda) { - _php_ibase_free_xsqlda(out_sqlda); - } - } - - return rv; -} -/* }}} */ - /* {{{ proto resource ibase_trans([int trans_args [, resource link_identifier [, ... ], int trans_args [, resource link_identifier [, ... ]] [, ...]]]) Start a transaction over one or several databases */ @@ -2297,844 +1136,6 @@ PHP_FUNCTION(ibase_rollback_ret) #endif /* }}} */ -/* {{{ proto mixed ibase_query([resource link_identifier, [ resource link_identifier, ]] string query [, mixed bind_arg [, mixed bind_arg [, ...]]]) - Execute a query */ -PHP_FUNCTION(ibase_query) -{ - zval ***args, **bind_args = NULL; - int i, bind_n = 0, trans_res_id = 0; - ibase_db_link *ib_link = NULL; - ibase_trans *trans = NULL; - ibase_query ib_query = { NULL, NULL, 0, 0 }; - ibase_result *result = NULL; - char *query; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() < 1) { - WRONG_PARAM_COUNT; - } - - /* use stack to avoid leaks */ - args = (zval ***) do_alloca(sizeof(zval **) * ZEND_NUM_ARGS()); - - RETVAL_FALSE; - - if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { - goto ibase_query_end; - - } - - i = 0; - while (Z_TYPE_PP(args[i++]) != IS_STRING) { - if (i >= ZEND_NUM_ARGS()) { - _php_ibase_module_error("Query argument missing" TSRMLS_CC); - goto ibase_query_end; - - } - } - - convert_to_string_ex(args[i-1]); - query = Z_STRVAL_PP(args[i-1]); - - /* find out if the first one or two arguments refer to either a link id, - a trans id or both */ - switch (i) { - case 1: - - /* no link ids were passed: if there's no default link, use exec_immediate() with - a NULL handle; this will enable the use of CREATE DATABASE statements. */ - if (IBG(default_link) == -1) { - isc_db_handle db = NULL; - isc_tr_handle trans = NULL; - - if (isc_dsql_execute_immediate(IB_STATUS, &db, &trans, 0, query, - SQL_DIALECT_CURRENT, NULL)) { - _php_ibase_error(TSRMLS_C); - goto ibase_query_end; - } - - /* has a new database been created ? */ - if (db != NULL) { - - if ((IBG(max_links) != -1) && (IBG(num_links) >= IBG(max_links))) { - - /* too many links already ? => close it up immediately */ - if (isc_detach_database(IB_STATUS, &db)) { - _php_ibase_error(TSRMLS_C); - goto ibase_query_end; - } - } else { - - /* register the link as a resource; unfortunately, we cannot register - it in the hash table, because we don't know the connection params */ - ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link)); - ib_link->handle = db; - ib_link->dialect = SQL_DIALECT_CURRENT; - ib_link->tr_list = NULL; - ib_link->event_head = NULL; - - ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link); - zend_list_addref(Z_LVAL_P(return_value)); - IBG(default_link) = Z_LVAL_P(return_value); - IBG(num_links)++; - goto ibase_query_end; - } - } - RETURN_TRUE; - } - - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", - le_link, le_plink); - break; - case 2: - /* one id was passed, could be db or trans id */ - _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, args[0], &ib_link, &trans); - - if (trans != NULL) { - /* argument was a trans id */ - convert_to_long_ex(args[0]); - trans_res_id = Z_LVAL_PP(args[0]); - } - break; - case 3: - /* two ids were passed, first should be link and second should be trans; */ - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, args[0], -1, "InterBase link", - le_link, le_plink); - ZEND_FETCH_RESOURCE(trans, ibase_trans*, args[1], -1, "InterBase transaction", le_trans); - - convert_to_long_ex(args[1]); - trans_res_id = Z_LVAL_PP(args[1]); - - break; - default: - /* more than two arguments preceed the SQL string */ - _php_ibase_module_error("Invalid arguments" TSRMLS_CC); - goto ibase_query_end; - } - - if (ZEND_NUM_ARGS() > i) { /* have variables to bind */ - bind_n = ZEND_NUM_ARGS() - i; - bind_args = args[i]; - } - - /* open default transaction */ - if (ib_link == NULL || _php_ibase_def_trans(ib_link, &trans TSRMLS_CC) == FAILURE) { - goto ibase_query_end; - } - - if (FAILURE == _php_ibase_alloc_query(&ib_query, ib_link, trans, query, ib_link->dialect, - trans_res_id TSRMLS_CC)) { - goto ibase_query_end; - } - - do { - if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, &ib_query, - bind_n, bind_args)) { - break; - } - - if (result != NULL) { /* statement returns a result */ - result->type = QUERY_RESULT; - - /* EXECUTE PROCEDURE returns only one row => statement can be released immediately */ - if (ib_query.statement_type != isc_info_sql_stmt_exec_procedure) { - ib_query.stmt = NULL; /* keep stmt when free query */ - } - ZEND_REGISTER_RESOURCE(return_value, result, le_result); - } - } while (0); - _php_ibase_free_query(&ib_query TSRMLS_CC); - -ibase_query_end: - free_alloca(args); -} -/* }}} */ - -/* {{{ proto int ibase_affected_rows( [ resource link_identifier ] ) - Returns the number of rows affected by the previous INSERT, UPDATE or DELETE statement */ -PHP_FUNCTION(ibase_affected_rows) -{ - ibase_trans *trans = NULL; - - RESET_ERRMSG; - - switch (ZEND_NUM_ARGS()) { - - ibase_db_link *ib_link; - zval **arg; - - case 0: - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", - le_link, le_plink); - if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { - RETURN_FALSE; - } - trans = ib_link->tr_list->trans; - break; - - case 1: - if (zend_get_parameters_ex(1, &arg) == FAILURE) { - RETURN_FALSE; - } - /* one id was passed, could be db or trans id */ - _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, arg, &ib_link, &trans); - if (trans == NULL) { - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, arg, -1, "InterBase link", - le_link, le_plink); - - if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { - RETURN_FALSE; - } - trans = ib_link->tr_list->trans; - } - break; - - default: - WRONG_PARAM_COUNT; - break; - } - RETURN_LONG(trans->affected_rows); -} -/* }}} */ - -/* {{{ proto int ibase_num_rows( resource result_identifier ) - Return the number of rows that are available in a result */ -#if abies_0 -PHP_FUNCTION(ibase_num_rows) -{ - /** - * As this function relies on the InterBase API function isc_dsql_sql_info() - * which has a couple of limitations (which I hope will be fixed in future - * releases of Firebird), this function is fairly useless. I'm leaving it - * in place for people who can live with the limitations, which I only - * found out about after I had implemented it anyway. - * - * Currently, there's no way to determine how many rows can be fetched from - * a cursor. The only number that _can_ be determined is the number of rows - * that have already been pre-fetched by the client library. - * This implies the following: - * - num_rows() always returns zero before the first fetch; - * - num_rows() for SELECT ... FOR UPDATE is broken -> never returns a - * higher number than the number of records fetched so far (no pre-fetch); - * - the result of num_rows() for other statements is merely a lower bound - * on the number of records => calling ibase_num_rows() again after a couple - * of fetches will most likely return a new (higher) figure for large result - * sets. - */ - - zval **result_arg; - ibase_result *ib_result; - static char info_count[] = {isc_info_sql_records}; - char result[64]; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result_arg) == FAILURE) { - WRONG_PARAM_COUNT; - } - - ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); - - if (isc_dsql_sql_info(IB_STATUS, &ib_result->stmt, sizeof(info_count), info_count, - sizeof(result), result)) { - _php_ibase_error(TSRMLS_C); - RETURN_FALSE; - } - - if (result[0] == isc_info_sql_records) { - unsigned i = 3, result_size = isc_vax_integer(&result[1],2); - - while (result[i] != isc_info_end && i < result_size) { - short len = (short)isc_vax_integer(&result[i+1],2); - if (result[i] == isc_info_req_select_count) { - RETURN_LONG(isc_vax_integer(&result[i+3],len)); - } - i += len+3; - } - } -} -#endif -/* }}} */ - -static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ */ - int scale, int flag TSRMLS_DC) -{ -#ifdef SQL_INT64 - static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000, - 1000000000, LL_LIT(10000000000),LL_LIT(100000000000),LL_LIT(10000000000000),LL_LIT(100000000000000), - LL_LIT(1000000000000000),LL_LIT(1000000000000000),LL_LIT(1000000000000000000) }; -#else - static long const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000, - 1000000000 }; -#endif - - switch (type & ~1) { - unsigned short l; - long n; - char string_data[255]; - struct tm t; - char *format; - - case SQL_VARYING: - len = ((IBVARY *) data)->vary_length; - data = ((IBVARY *) data)->vary_string; - /* no break */ - case SQL_TEXT: - if (PG(magic_quotes_runtime)) { - Z_STRVAL_P(val) = php_addslashes(data, len, &Z_STRLEN_P(val), 0 TSRMLS_CC); - Z_TYPE_P(val) = IS_STRING; - } else { - ZVAL_STRINGL(val,(char *) data,len,1); - } - break; - case SQL_SHORT: - n = *(short *) data; - goto _sql_long; -#ifdef SQL_INT64 - case SQL_INT64: -#if (SIZEOF_LONG >= 8) - n = *(long *) data; - goto _sql_long; -#else - if (scale == 0) { - l = sprintf(string_data, "%" LL_MASK "d", *(ISC_INT64 *) data); - ZVAL_STRINGL(val,string_data,l,1); - } else { - ISC_INT64 n = *(ISC_INT64 *) data, f = scales[-scale]; - - if (n >= 0) { - l = sprintf(string_data, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, n % f); - } else if (n < -f) { - l = sprintf(string_data, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, -n % f); - } else { - l = sprintf(string_data, "-0.%0*" LL_MASK "d", -scale, -n % f); - } - ZVAL_STRINGL(val,string_data,l,1); - } - break; -#endif -#endif - case SQL_LONG: - n = *(ISC_LONG *) data; - _sql_long: - if (scale == 0) { - ZVAL_LONG(val,n); - } else { - long f = (long) scales[-scale]; - - if (n >= 0) { - l = sprintf(string_data, "%ld.%0*ld", n / f, -scale, n % f); - } else if (n < -f) { - l = sprintf(string_data, "%ld.%0*ld", n / f, -scale, -n % f); - } else { - l = sprintf(string_data, "-0.%0*ld", -scale, -n % f); - } - ZVAL_STRINGL(val,string_data,l,1); - } - break; - case SQL_FLOAT: - ZVAL_DOUBLE(val, *(float *) data); - break; - case SQL_DOUBLE: - ZVAL_DOUBLE(val, *(double *) data); - break; - case SQL_DATE: /* == case SQL_TIMESTAMP: */ - format = IBG(timestampformat); -#ifndef SQL_TIMESTAMP - isc_decode_date((ISC_QUAD *) data, &t); -#else - isc_decode_timestamp((ISC_TIMESTAMP *) data, &t); - goto format_date_time; - case SQL_TYPE_DATE: - format = IBG(dateformat); - isc_decode_sql_date((ISC_DATE *) data, &t); - goto format_date_time; - case SQL_TYPE_TIME: - format = IBG(timeformat); - isc_decode_sql_time((ISC_TIME *) data, &t); - -format_date_time: -#endif - /* - XXX - Might have to remove this later - seems that isc_decode_date() - always sets tm_isdst to 0, sometimes incorrectly (InterBase 6 bug?) - */ - t.tm_isdst = -1; -#if HAVE_TM_ZONE - t.tm_zone = tzname[0]; -#endif - if (flag & PHP_IBASE_UNIXTIME) { - ZVAL_LONG(val, mktime(&t)); - } else { -#if HAVE_STRFTIME - l = strftime(string_data, sizeof(string_data), format, &t); -#else - switch (type & ~1) { - default: - l = sprintf(string_data, "%02d/%02d/%4d %02d:%02d:%02d", t.tm_mon+1, t.tm_mday, - t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec); - break; -#ifdef SQL_TIMESTAMP - case SQL_TYPE_DATE: - l = sprintf(string_data, "%02d/%02d/%4d", t.tm_mon + 1, t.tm_mday, t.tm_year+1900); - break; - case SQL_TYPE_TIME: - l = sprintf(string_data, "%02d:%02d:%02d", t.tm_hour, t.tm_min, t.tm_sec); - break; -#endif - } -#endif - ZVAL_STRINGL(val,string_data,l,1); - break; - } - } /* switch (type) */ - return SUCCESS; -} -/* }}} */ - -static int _php_ibase_arr_zval(zval *ar_zval, char *data, unsigned long data_size, /* {{{ */ - ibase_array *ib_array, int dim, int flag TSRMLS_DC) -{ - /** - * Create multidimension array - recursion function - */ - int - u_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_upper, - l_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_lower, - dim_len = 1 + u_bound - l_bound; - unsigned short i; - - if (dim < ib_array->ar_desc.array_desc_dimensions) { /* array again */ - unsigned long slice_size = data_size / dim_len; - - array_init(ar_zval); - - for (i = 0; i < dim_len; ++i) { - zval *slice_zval; - ALLOC_INIT_ZVAL(slice_zval); - - /* recursion here */ - if (FAILURE == _php_ibase_arr_zval(slice_zval, data, slice_size, ib_array, dim + 1, - flag TSRMLS_CC)) { - return FAILURE; - } - data += slice_size; - - add_index_zval(ar_zval,l_bound+i,slice_zval); - } - } else { /* data at last */ - - if (FAILURE == _php_ibase_var_zval(ar_zval, data, ib_array->el_type, - ib_array->ar_desc.array_desc_length, ib_array->ar_desc.array_desc_scale, flag TSRMLS_CC)) { - return FAILURE; - } - - /* fix for peculiar handling of VARCHAR arrays; - truncate the field to the cstring length */ - if (ib_array->ar_desc.array_desc_dtype == blr_varying || - ib_array->ar_desc.array_desc_dtype == blr_varying2) { - - Z_STRLEN_P(ar_zval) = strlen(Z_STRVAL_P(ar_zval)); - } - } - return SUCCESS; -} -/* }}} */ - -static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type) /* {{{ */ -{ - zval **result_arg, **flag_arg; - long i, array_cnt = 0, flag = 0; - ibase_result *ib_result; - - RESET_ERRMSG; - - switch (ZEND_NUM_ARGS()) { - case 1: - if (FAILURE == zend_get_parameters_ex(1, &result_arg)) { - RETURN_FALSE; - } - break; - case 2: - if (FAILURE == zend_get_parameters_ex(2, &result_arg, &flag_arg)) { - RETURN_FALSE; - } - convert_to_long_ex(flag_arg); - flag = Z_LVAL_PP(flag_arg); - break; - default: - WRONG_PARAM_COUNT; - break; - } - - ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); - - if (ib_result->out_sqlda == NULL || !ib_result->has_more_rows) { - RETURN_FALSE; - } - - if (ib_result->statement_type != isc_info_sql_stmt_exec_procedure) { - - if (isc_dsql_fetch(IB_STATUS, &ib_result->stmt, 1, ib_result->out_sqlda)) { - - ib_result->has_more_rows = 0; - if (IB_STATUS[0] && IB_STATUS[1]) { /* error in fetch */ - _php_ibase_error(TSRMLS_C); - } - RETURN_FALSE; - } - } else { - ib_result->has_more_rows = 0; - } - - array_init(return_value); - - for (i = 0; i < ib_result->out_sqlda->sqld; ++i) { - XSQLVAR *var = &ib_result->out_sqlda->sqlvar[i]; - - if (((var->sqltype & 1) == 0) || *var->sqlind != -1) { - zval *result; - ALLOC_INIT_ZVAL(result); - - switch (var->sqltype & ~1) { - - default: - _php_ibase_var_zval(result, var->sqldata, var->sqltype, var->sqllen, - var->sqlscale, flag TSRMLS_CC); - break; - case SQL_BLOB: - if (flag & PHP_IBASE_FETCH_BLOBS) { /* fetch blob contents into hash */ - - ibase_blob blob_handle; - unsigned long max_len = 0; - static char bl_items[] = {isc_info_blob_total_length}; - char bl_info[20]; - unsigned short i; - - blob_handle.bl_handle = NULL; - blob_handle.bl_qd = *(ISC_QUAD *) var->sqldata; - - if (isc_open_blob(IB_STATUS, &ib_result->link->handle, &ib_result->trans->handle, - &blob_handle.bl_handle, &blob_handle.bl_qd)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_fetch_error; - } - - if (isc_blob_info(IB_STATUS, &blob_handle.bl_handle, sizeof(bl_items), - bl_items, sizeof(bl_info), bl_info)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_fetch_error; - } - - /* find total length of blob's data */ - for (i = 0; i < sizeof(bl_info); ) { - unsigned short item_len; - char item = bl_info[i++]; - - if (item == isc_info_end || item == isc_info_truncated || - item == isc_info_error || i >= sizeof(bl_info)) { - - _php_ibase_module_error("Could not determine BLOB size (internal error)" - TSRMLS_CC); - goto _php_ibase_fetch_error; - } - - item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2); - - if (item == isc_info_blob_total_length) { - max_len = isc_vax_integer(&bl_info[i+2], item_len); - break; - } - i += item_len+2; - } - - if (max_len == 0) { - ZVAL_STRING(result, "", 1); - } else if (SUCCESS != _php_ibase_blob_get(result, &blob_handle, - max_len TSRMLS_CC)) { - goto _php_ibase_fetch_error; - } - - if (isc_close_blob(IB_STATUS, &blob_handle.bl_handle)) { - _php_ibase_error(TSRMLS_C); - goto _php_ibase_fetch_error; - } - - } else { /* blob id only */ - ISC_QUAD bl_qd = *(ISC_QUAD *) var->sqldata; - ZVAL_STRINGL(result,_php_ibase_quad_to_string(bl_qd), BLOB_ID_LEN, 0); - } - break; - case SQL_ARRAY: - if (flag & PHP_IBASE_FETCH_ARRAYS) { /* array can be *huge* so only fetch if asked */ - ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata; - ibase_array *ib_array = &ib_result->out_array[array_cnt++]; - void *ar_data = emalloc(ib_array->ar_size); - - if (isc_array_get_slice(IB_STATUS, &ib_result->link->handle, - &ib_result->trans->handle, &ar_qd, &ib_array->ar_desc, - ar_data, &ib_array->ar_size)) { - _php_ibase_error(TSRMLS_C); - efree(ar_data); - goto _php_ibase_fetch_error; - } - - if (FAILURE == _php_ibase_arr_zval(result, ar_data, ib_array->ar_size, ib_array, - 0, flag TSRMLS_CC)) { - efree(ar_data); - goto _php_ibase_fetch_error; - } - efree(ar_data); - - } else { /* blob id only */ - ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata; - ZVAL_STRINGL(result,_php_ibase_quad_to_string(ar_qd), BLOB_ID_LEN, 0); - } - break; - _php_ibase_fetch_error: - zval_dtor(result); - FREE_ZVAL(result); - RETURN_FALSE; - } /* switch */ - - if (fetch_type & FETCH_ROW) { - add_index_zval(return_value, i, result); - } else { - add_assoc_zval(return_value, var->aliasname, result); - } - } else { - if (fetch_type & FETCH_ROW) { - add_index_null(return_value, i); - } else { - add_assoc_null(return_value, var->aliasname); - } - } - } /* for field */ -} -/* }}} */ - -/* {{{ proto array ibase_fetch_row(resource result [, int fetch_flags]) - Fetch a row from the results of a query */ -PHP_FUNCTION(ibase_fetch_row) -{ - _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ROW); -} -/* }}} */ - -/* {{{ proto array ibase_fetch_assoc(resource result [, int fetch_flags]) - Fetch a row from the results of a query */ -PHP_FUNCTION(ibase_fetch_assoc) -{ - _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY); -} -/* }}} */ - -/* {{{ proto object ibase_fetch_object(resource result [, int fetch_flags]) - Fetch a object from the results of a query */ -PHP_FUNCTION(ibase_fetch_object) -{ - _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY); - - if (Z_TYPE_P(return_value) == IS_ARRAY) { - object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value)); - } -} -/* }}} */ - - -/* {{{ proto bool ibase_name_result(resource result, string name) - Assign a name to a result for use with ... WHERE CURRENT OF statements */ -PHP_FUNCTION(ibase_name_result) -{ - zval **result_arg, **name_arg; - ibase_result *ib_result; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result_arg, &name_arg) == FAILURE) { - WRONG_PARAM_COUNT; - } - - ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); - convert_to_string_ex(name_arg); - - if (isc_dsql_set_cursor_name(IB_STATUS, &ib_result->stmt, Z_STRVAL_PP(name_arg), 0)) { - _php_ibase_error(TSRMLS_C); - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - - -/* {{{ proto bool ibase_free_result(resource result) - Free the memory used by a result */ -PHP_FUNCTION(ibase_free_result) -{ - zval **result_arg; - ibase_result *ib_result; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result_arg) == FAILURE) { - WRONG_PARAM_COUNT; - } - - ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); - zend_list_delete(Z_LVAL_PP(result_arg)); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto resource ibase_prepare([resource link_identifier, ] string query) - Prepare a query for later execution */ -PHP_FUNCTION(ibase_prepare) -{ - zval **link_arg, **trans_arg, **query_arg; - ibase_db_link *ib_link; - ibase_trans *trans = NULL; - int trans_res_id = 0; - ibase_query *ib_query; - char *query; - - RESET_ERRMSG; - - switch (ZEND_NUM_ARGS()) { - case 1: - if (zend_get_parameters_ex(1, &query_arg) == FAILURE) { - RETURN_FALSE; - } - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", - le_link, le_plink); - break; - case 2: - if (zend_get_parameters_ex(2, &link_arg, &query_arg) == FAILURE) { - RETURN_FALSE; - } - _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, link_arg, &ib_link, &trans); - - if (trans != NULL) { - convert_to_long_ex(link_arg); - trans_res_id = Z_LVAL_PP(link_arg); - } - - break; - case 3: - if (zend_get_parameters_ex(3, &link_arg, &trans_arg, &query_arg) == FAILURE) { - RETURN_FALSE; - } - ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, link_arg, -1, "InterBase link", - le_link, le_plink); - ZEND_FETCH_RESOURCE(trans, ibase_trans*, trans_arg, -1, "InterBase transaction", le_trans); - - convert_to_long_ex(trans_arg); - trans_res_id = Z_LVAL_PP(trans_arg); - - break; - default: - WRONG_PARAM_COUNT; - break; - } - - convert_to_string_ex(query_arg); - query = Z_STRVAL_PP(query_arg); - - if (FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC)) { - RETURN_FALSE; - } - - ib_query = (ibase_query *) emalloc(sizeof(ibase_query)); - - if (FAILURE == _php_ibase_alloc_query(ib_query, ib_link, trans, query, ib_link->dialect, - trans_res_id TSRMLS_CC)) { - efree(ib_query); - RETURN_FALSE; - } - ZEND_REGISTER_RESOURCE(return_value, ib_query, le_query); -} -/* }}} */ - -/* {{{ proto mixed ibase_execute(resource query [, mixed bind_arg [, mixed bind_arg [, ...]]]) - Execute a previously prepared query */ -PHP_FUNCTION(ibase_execute) -{ - zval ***args, **bind_args = NULL; - ibase_query *ib_query; - ibase_result *result = NULL; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() < 1) { - WRONG_PARAM_COUNT; - } - - /* use stack to avoid leaks */ - args = (zval ***) do_alloca(ZEND_NUM_ARGS() * sizeof(zval **)); - if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { - free_alloca(args); - RETURN_FALSE; - } - - ZEND_FETCH_RESOURCE(ib_query, ibase_query *, args[0], -1, "InterBase query", le_query); - - if (ZEND_NUM_ARGS() > 1) { /* have variables to bind */ - bind_args = args[1]; - } - - /* Have we used this cursor before and it's still open (exec proc has no cursor) ? */ - if (ib_query->result_res_id != 0 && ib_query->statement_type != isc_info_sql_stmt_exec_procedure) { - IBDEBUG("Implicitly closing a cursor"); - if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_close)) { - _php_ibase_error(TSRMLS_C); - } - /* invalidate previous results returned by this query (not necessary for exec proc) */ - zend_list_delete(ib_query->result_res_id); - } - - if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, ib_query, - ZEND_NUM_ARGS()-1, bind_args)) { - free_alloca(args); - RETURN_FALSE; - } - - /* free the query if trans handle was released */ - if (ib_query->trans->handle == NULL) { - zend_list_delete(Z_LVAL_PP(args[0])); - } - - free_alloca(args); - - if (result != NULL) { - result->type = EXECUTE_RESULT; - if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) { - result->stmt = NULL; - } - ib_query->result_res_id = zend_list_insert(result, le_result); - RETURN_RESOURCE(ib_query->result_res_id); - } -} -/* }}} */ - -/* {{{ proto bool ibase_free_query(resource query) - Free memory used by a query */ -PHP_FUNCTION(ibase_free_query) -{ - zval **query_arg; - ibase_query *ib_query; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &query_arg) == FAILURE) { - WRONG_PARAM_COUNT; - } - - ZEND_FETCH_RESOURCE(ib_query, ibase_query *, query_arg, -1, "InterBase query", le_query); - zend_list_delete(Z_LVAL_PP(query_arg)); - RETURN_TRUE; -} -/* }}} */ - #if HAVE_STRFTIME /* {{{ proto bool ibase_timefmt(string format [, int type ]) Sets the format of timestamp, date and time columns returned from queries */ @@ -3190,233 +1191,6 @@ PHP_FUNCTION(ibase_timefmt) /* }}} */ #endif -/* {{{ proto int ibase_num_fields(resource query_result) - Get the number of fields in result */ -PHP_FUNCTION(ibase_num_fields) -{ - zval **result; - int type; - XSQLDA *sqlda; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &result)==FAILURE) { - WRONG_PARAM_COUNT; - } - - zend_list_find(Z_LVAL_PP(result), &type); - - if (type == le_query) { - ibase_query *ib_query; - - ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result, -1, "InterBase query", le_query); - sqlda = ib_query->out_sqlda; - } else { - ibase_result *ib_result; - - ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result, -1, "InterBase result", le_result); - sqlda = ib_result->out_sqlda; - } - - if (sqlda == NULL) { - RETURN_LONG(0); - } else { - RETURN_LONG(sqlda->sqld); - } -} -/* }}} */ - -static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */ -{ - unsigned short len; - char buf[16], *s = buf; - - array_init(return_value); - - add_index_stringl(return_value, 0, var->sqlname, var->sqlname_length, 1); - add_assoc_stringl(return_value, "name", var->sqlname, var->sqlname_length, 1); - - add_index_stringl(return_value, 1, var->aliasname, var->aliasname_length, 1); - add_assoc_stringl(return_value, "alias", var->aliasname, var->aliasname_length, 1); - - add_index_stringl(return_value, 2, var->relname, var->relname_length, 1); - add_assoc_stringl(return_value, "relation", var->relname, var->relname_length, 1); - - len = sprintf(buf, "%d", var->sqllen); - add_index_stringl(return_value, 3, buf, len, 1); - add_assoc_stringl(return_value, "length", buf, len, 1); - - if (var->sqlscale < 0) { - unsigned short precision = 0; - - switch (var->sqltype & ~1) { - - case SQL_SHORT: - precision = 4; - break; - case SQL_LONG: - precision = 9; - break; -#ifdef SQL_INT64 - case SQL_INT64: - precision = 18; - break; -#endif - } - len = sprintf(buf, "NUMERIC(%d,%d)", precision, -var->sqlscale); - add_index_stringl(return_value, 4, s, len, 1); - add_assoc_stringl(return_value, "type", s, len, 1); - } else { - switch (var->sqltype & ~1) { - case SQL_TEXT: - s = "CHAR"; - break; - case SQL_VARYING: - s = "VARCHAR"; - break; - case SQL_SHORT: - s = "SMALLINT"; - break; - case SQL_LONG: - s = "INTEGER"; - break; - case SQL_FLOAT: - s = "FLOAT"; break; - case SQL_DOUBLE: - case SQL_D_FLOAT: - s = "DOUBLE PRECISION"; break; -#ifdef SQL_INT64 - case SQL_INT64: - s = "BIGINT"; - break; -#endif -#ifdef SQL_TIMESTAMP - case SQL_TIMESTAMP: - s = "TIMESTAMP"; - break; - case SQL_TYPE_DATE: - s = "DATE"; - break; - case SQL_TYPE_TIME: - s = "TIME"; - break; -#else - case SQL_DATE: - s = "DATE"; - break; -#endif - case SQL_BLOB: - s = "BLOB"; - break; - case SQL_ARRAY: - s = "ARRAY"; - break; - /* FIXME: provide more detailed information about the field type, field size - * and array dimensions */ - case SQL_QUAD: - s = "QUAD"; - break; - } - add_index_string(return_value, 4, s, 1); - add_assoc_string(return_value, "type", s, 1); - } -} -/* }}} */ - -/* {{{ proto array ibase_field_info(resource query_result, int field_number) - Get information about a field */ -PHP_FUNCTION(ibase_field_info) -{ - zval **result_arg, **field_arg; - int type; - XSQLDA *sqlda; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &result_arg, &field_arg)==FAILURE) { - WRONG_PARAM_COUNT; - } - - zend_list_find(Z_LVAL_PP(result_arg), &type); - - if (type == le_query) { - ibase_query *ib_query; - - ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result_arg, -1, "InterBase query", le_query); - sqlda = ib_query->out_sqlda; - } else { - ibase_result *ib_result; - - ZEND_FETCH_RESOURCE(ib_result, ibase_result *, result_arg, -1, "InterBase result", le_result); - sqlda = ib_result->out_sqlda; - } - - if (sqlda == NULL) { - _php_ibase_module_error("Trying to get field info from a non-select query" TSRMLS_CC); - RETURN_FALSE; - } - - convert_to_long_ex(field_arg); - - if (Z_LVAL_PP(field_arg) < 0 || Z_LVAL_PP(field_arg) >= sqlda->sqld) { - RETURN_FALSE; - } - _php_ibase_field_info(return_value,sqlda->sqlvar + Z_LVAL_PP(field_arg)); -} -/* }}} */ - -/* {{{ proto int ibase_num_params(resource query) - Get the number of params in a prepared query */ -PHP_FUNCTION(ibase_num_params) -{ - zval **result; - ibase_query *ib_query; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &result) == FAILURE) { - WRONG_PARAM_COUNT; - } - - ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result, -1, "InterBase query", le_query); - - if (ib_query->in_sqlda == NULL) { - RETURN_LONG(0); - } else { - RETURN_LONG(ib_query->in_sqlda->sqld); - } -} -/* }}} */ - -/* {{{ proto array ibase_param_info(resource query, int field_number) - Get information about a parameter */ -PHP_FUNCTION(ibase_param_info) -{ - zval **result_arg, **field_arg; - ibase_query *ib_query; - - RESET_ERRMSG; - - if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result_arg, &field_arg) == FAILURE) { - WRONG_PARAM_COUNT; - } - - ZEND_FETCH_RESOURCE(ib_query, ibase_query *, result_arg, -1, "InterBase query", le_query); - - if (ib_query->in_sqlda == NULL) { - RETURN_FALSE; - } - - convert_to_long_ex(field_arg); - - if (Z_LVAL_PP(field_arg) < 0 || Z_LVAL_PP(field_arg) >= ib_query->in_sqlda->sqld) { - RETURN_FALSE; - } - - _php_ibase_field_info(return_value,ib_query->in_sqlda->sqlvar + Z_LVAL_PP(field_arg)); -} -/* }}} */ - /* {{{ proto int ibase_gen_id(string generator [, int increment [, resource link_identifier ]]) Increments the named generator and returns its new value */ PHP_FUNCTION(ibase_gen_id) diff --git a/ext/interbase/php_ibase_includes.h b/ext/interbase/php_ibase_includes.h index b0b0ea31115..acc537aaedf 100755 --- a/ext/interbase/php_ibase_includes.h +++ b/ext/interbase/php_ibase_includes.h @@ -46,8 +46,15 @@ typedef unsigned long long ISC_UINT64; #define IB_STATUS (IBG(status)) -extern int le_blob, le_link, le_plink, le_result, le_query, le_trans, - le_event, le_service; +#ifdef ZEND_DEBUG_ +#define IBDEBUG(a) php_printf("::: %s (%d)\n", a, __LINE__); +#endif + +#ifndef IBDEBUG +#define IBDEBUG(a) +#endif + +extern int le_link, le_plink, le_trans; #define IBASE_MSGSIZE 256 #define MAX_ERRMSG (IBASE_MSGSIZE*2) @@ -154,7 +161,7 @@ enum php_interbase_option { PHP_IBASE_TIMESTAMP = 1, PHP_IBASE_DATE = 2, PHP_IBASE_TIME = 4, - /* transaction access mode */ + /* transaction access mode */ PHP_IBASE_WRITE = 1, PHP_IBASE_READ = 2, /* transaction isolation level */ @@ -190,14 +197,9 @@ typedef void (__stdcall *info_func_t)(char*); typedef void (*info_func_t)(char*); #endif -int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd); -char *_php_ibase_quad_to_string(ISC_QUAD const qd); -int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, unsigned long max_len TSRMLS_DC); -int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC); - -void _php_ibase_error(TSRMLS_D); -void _php_ibase_module_error(char * TSRMLS_DC, ...) - PHP_ATTRIBUTE_FORMAT(printf,1,PHP_ATTR_FMT_OFFSET +2); +PHPAPI void _php_ibase_error(TSRMLS_D); +PHPAPI void _php_ibase_module_error(char * TSRMLS_DC, ...) + PHP_ATTRIBUTE_FORMAT(printf,1,PHP_ATTR_FMT_OFFSET +2); /* determine if a resource is a link or transaction handle */ #define PHP_IBASE_LINK_TRANS(pzval, lh, th) \ @@ -208,12 +210,27 @@ void _php_ibase_module_error(char * TSRMLS_DC, ...) _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &pzval, &lh, &th); \ if (SUCCESS != _php_ibase_def_trans(lh, &th TSRMLS_CC)) { RETURN_FALSE; } \ } while (0) - -int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans TSRMLS_DC); -void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, zval **link_id, + +PHPAPI int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans TSRMLS_DC); +PHPAPI void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, zval **link_id, ibase_db_link **ib_link, ibase_trans **trans); -void _php_ibase_event_free(char *event_buf, char *result_buf); +/* provided by ibase_query.c */ +void php_ibase_query_minit(INIT_FUNC_ARGS); + +/* provided by ibase_blobs.c */ +void php_ibase_blobs_minit(INIT_FUNC_ARGS); +PHPAPI int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd); +PHPAPI char *_php_ibase_quad_to_string(ISC_QUAD const qd); +PHPAPI int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, unsigned long max_len TSRMLS_DC); +PHPAPI int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC); + +/* provided by ibase_events.c */ +void php_ibase_events_minit(INIT_FUNC_ARGS); +PHPAPI void _php_ibase_free_event(ibase_event *event TSRMLS_DC); + +/* provided by ibase_service.c */ +void php_ibase_service_minit(INIT_FUNC_ARGS); #ifndef max #define max(a,b) ((a)>(b)?(a):(b))