From 6fa585ed2e9f0d8f8a8ba5d9ec128534abfeb25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sat, 1 Mar 2025 00:16:22 +0200 Subject: [PATCH 01/24] Emit warning about unhandled sqltype --- ibase_query.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ibase_query.c b/ibase_query.c index f959848..b17423b 100644 --- a/ibase_query.c +++ b/ibase_query.c @@ -922,9 +922,9 @@ static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */ break; // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - case SQL_BOOLEAN: - var->sqldata = emalloc(sizeof(FB_BOOLEAN)); - break; + case SQL_BOOLEAN: + var->sqldata = emalloc(sizeof(FB_BOOLEAN)); + break; #endif case SQL_SHORT: var->sqldata = emalloc(sizeof(short)); @@ -954,6 +954,9 @@ static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */ case SQL_ARRAY: var->sqldata = emalloc(sizeof(ISC_QUAD)); break; + default: + php_error(E_WARNING, "Unhandled sqltype: %d for sqlname %s %s:%d. This is most likely due to this PHP driver has been not kept up with newer server version", var->sqltype, var->sqlname, __FILE__, __LINE__); + break; } /* switch */ if (var->sqltype & 1) { /* sql NULL flag */ @@ -1055,7 +1058,7 @@ static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resul res->trans = ib_query->trans; res->stmt = ib_query->stmt; GC_ADDREF(res->stmt_res = ib_query->stmt_res); - + res->statement_type = ib_query->statement_type; res->has_more_rows = 1; @@ -1811,7 +1814,7 @@ PHP_FUNCTION(ibase_free_result) ib_result = (ibase_result *)zend_fetch_resource_ex(result_arg, LE_RESULT, le_result); zend_list_delete(Z_RES_P(result_arg)); - + /* * Bugfix of issue #40 * Reset pointer after freeing to NULL From f15b98d3017fdaf03b49adb5b498050c9e84f564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sat, 1 Mar 2025 00:25:59 +0200 Subject: [PATCH 02/24] Ignore .dep files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 684a972..110ac07 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ yaml.loT .FBCIndex .FBCLockFolder core +*.dep # Test specific Ignores tests/*.diff From 6ccbde7b18d5ca44af6e8f16511007df34dee3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sat, 1 Mar 2025 22:42:34 +0200 Subject: [PATCH 03/24] Borrow pdo_firebird_utils.cpp from PDO_Firebird --- config.m4 | 18 +++++++++- config.w32 | 2 +- pdo_firebird_utils.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++ pdo_firebird_utils.h | 48 +++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 pdo_firebird_utils.cpp create mode 100644 pdo_firebird_utils.h diff --git a/config.m4 b/config.m4 index 74e62e8..0ba0ca9 100644 --- a/config.m4 +++ b/config.m4 @@ -54,6 +54,22 @@ if test "$PHP_INTERBASE" != "no"; then fi AC_DEFINE(HAVE_IBASE,1,[ ]) - PHP_NEW_EXTENSION(interbase, interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) + PHP_NEW_EXTENSION(interbase, interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1,[cxx]) PHP_SUBST(INTERBASE_SHARED_LIBADD) + + PHP_REQUIRE_CXX() + PHP_CXX_COMPILE_STDCXX([11], [mandatory], [PHP_INTERBASE_STDCXX]) + + PHP_INTERBASE_CXX_SOURCES="pdo_firebird_utils.cpp" + + AS_VAR_IF([ext_shared], [no], + [PHP_ADD_SOURCES([$ext_dir], + [$PHP_INTERBASE_CXX_SOURCES], + [$PHP_INTERBASE_STDCXX])], + [PHP_ADD_SOURCES_X([$ext_dir], + [$PHP_INTERBASE_CXX_SOURCES], + [$PHP_INTERBASE_STDCXX], + [shared_objects_interbase], + [yes])]) + fi diff --git a/config.w32 b/config.w32 index c1f5a91..0cca7e7 100644 --- a/config.w32 +++ b/config.w32 @@ -9,7 +9,7 @@ if (PHP_INTERBASE != "no") { (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_query.c ibase_service.c ibase_events.c ibase_blobs.c", PHP_INTERBASE_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + EXTENSION("interbase", "interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c pdo_firebird_utils.cpp", PHP_INTERBASE_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE('HAVE_IBASE', 1, 'Have interbase library'); } else { WARNING("interbase not enabled; libraries and headers not found"); diff --git a/pdo_firebird_utils.cpp b/pdo_firebird_utils.cpp new file mode 100644 index 0000000..fc1bde5 --- /dev/null +++ b/pdo_firebird_utils.cpp @@ -0,0 +1,81 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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: | + | https://www.php.net/license/3_01.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. | + +----------------------------------------------------------------------+ + | Author: Simonov Denis | + +----------------------------------------------------------------------+ +*/ + +#include "pdo_firebird_utils.h" +#include +#include + +/* Returns the client version. 0 bytes are minor version, 1 bytes are major version. */ +extern "C" unsigned fb_get_client_version(void) +{ + Firebird::IMaster* master = Firebird::fb_get_master_interface(); + Firebird::IUtil* util = master->getUtilInterface(); + return util->getClientVersion(); +} + +extern "C" ISC_TIME fb_encode_time(unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions) +{ + Firebird::IMaster* master = Firebird::fb_get_master_interface(); + Firebird::IUtil* util = master->getUtilInterface(); + return util->encodeTime(hours, minutes, seconds, fractions); +} + +extern "C" ISC_DATE fb_encode_date(unsigned year, unsigned month, unsigned day) +{ + Firebird::IMaster* master = Firebird::fb_get_master_interface(); + Firebird::IUtil* util = master->getUtilInterface(); + return util->encodeDate(year, month, day); +} + +#if FB_API_VER >= 40 +static void fb_copy_status(const ISC_STATUS* from, ISC_STATUS* to, size_t maxLength) +{ + for(size_t i=0; i < maxLength; ++i) { + memcpy(to + i, from + i, sizeof(ISC_STATUS)); + if (from[i] == isc_arg_end) { + break; + } + } +} + +/* Decodes a time with time zone into its time components. */ +extern "C" void fb_decode_time_tz(const ISC_TIME_TZ* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, + unsigned timeZoneBufferLength, char* timeZoneBuffer) +{ + Firebird::IMaster* master = Firebird::fb_get_master_interface(); + Firebird::IUtil* util = master->getUtilInterface(); + Firebird::IStatus* status = master->getStatus(); + Firebird::CheckStatusWrapper st(status); + util->decodeTimeTz(&st, timeTz, hours, minutes, seconds, fractions, + timeZoneBufferLength, timeZoneBuffer); +} + +/* Decodes a timestamp with time zone into its date and time components */ +extern "C" void fb_decode_timestamp_tz(const ISC_TIMESTAMP_TZ* timestampTz, + unsigned* year, unsigned* month, unsigned* day, + unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, + unsigned timeZoneBufferLength, char* timeZoneBuffer) +{ + Firebird::IMaster* master = Firebird::fb_get_master_interface(); + Firebird::IUtil* util = master->getUtilInterface(); + Firebird::IStatus* status = master->getStatus(); + Firebird::CheckStatusWrapper st(status); + util->decodeTimeStampTz(&st, timestampTz, year, month, day, + hours, minutes, seconds, fractions, + timeZoneBufferLength, timeZoneBuffer); +} + +#endif diff --git a/pdo_firebird_utils.h b/pdo_firebird_utils.h new file mode 100644 index 0000000..197b279 --- /dev/null +++ b/pdo_firebird_utils.h @@ -0,0 +1,48 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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: | + | https://www.php.net/license/3_01.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. | + +----------------------------------------------------------------------+ + | Author: Simonov Denis | + +----------------------------------------------------------------------+ +*/ + +#ifndef PDO_FIREBIRD_UTILS_H +#define PDO_FIREBIRD_UTILS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned fb_get_client_version(void); + +ISC_TIME fb_encode_time(unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions); + +ISC_DATE fb_encode_date(unsigned year, unsigned month, unsigned day); + +#if FB_API_VER >= 40 + +void fb_decode_time_tz(const ISC_TIME_TZ* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, + unsigned timeZoneBufferLength, char* timeZoneBuffer); + +void fb_decode_timestamp_tz(const ISC_TIMESTAMP_TZ* timestampTz, + unsigned* year, unsigned* month, unsigned* day, + unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, + unsigned timeZoneBufferLength, char* timeZoneBuffer); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PDO_FIREBIRD_UTILS_H */ From 0e025658008e678a3cee3aeb029fe6fbe2379e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sat, 1 Mar 2025 22:46:00 +0200 Subject: [PATCH 04/24] Add TIME_TZ SQL_TIMESTAMP_TZ types --- ibase_query.c | 133 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 19 deletions(-) diff --git a/ibase_query.c b/ibase_query.c index b17423b..5e7ca94 100644 --- a/ibase_query.c +++ b/ibase_query.c @@ -37,6 +37,7 @@ #include "ext/standard/php_standard.h" #include "php_interbase.h" #include "php_ibase_includes.h" +#include "pdo_firebird_utils.h" #define ISC_LONG_MIN INT_MIN #define ISC_LONG_MAX INT_MAX @@ -266,10 +267,10 @@ static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ break; // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - case blr_bool: - a->el_type = SQL_BOOLEAN; - a->el_size = sizeof(FB_BOOLEAN); - break; + case blr_bool: + a->el_type = SQL_BOOLEAN; + a->el_size = sizeof(FB_BOOLEAN); + break; #endif case blr_short: a->el_type = SQL_SHORT; @@ -303,6 +304,20 @@ static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ a->el_type = SQL_TYPE_TIME; a->el_size = sizeof(ISC_TIME); break; +#if FB_API_VER >= 40 + // These are converted to VARCHAR via isc_dpb_set_bind tag at connect + // blr_dec64 + // blr_dec128 + // blr_int128 + case blr_sql_time_tz: + a->el_type = SQL_TIME_TZ; + a->el_size = sizeof(ISC_TIME_TZ); + break; + case blr_timestamp_tz: + a->el_type = SQL_TIMESTAMP_TZ; + a->el_size = sizeof(ISC_TIMESTAMP_TZ); + break; +#endif case blr_varying: case blr_varying2: /** @@ -614,17 +629,19 @@ static int _php_ibase_bind_array(zval *val, char *buf, zend_ulong buf_size, /* { break; // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - case SQL_BOOLEAN: - convert_to_boolean(val); - // On Windows error unresolved symbol Z_BVAL_P is thrown, so we use Z_LVAL_P - *(FB_BOOLEAN*) buf = Z_LVAL_P(val); - break; + case SQL_BOOLEAN: + convert_to_boolean(val); + // On Windows error unresolved symbol Z_BVAL_P is thrown, so we use Z_LVAL_P + *(FB_BOOLEAN*) buf = Z_LVAL_P(val); + break; #endif case SQL_DOUBLE: convert_to_double(val); *(double*) buf = Z_DVAL_P(val); break; case SQL_TIMESTAMP: + // TODO: + // case SQL_TIMESTAMP_TZ: convert_to_string(val); #ifdef HAVE_STRPTIME strptime(Z_STRVAL_P(val), INI_STR("ibase.timestampformat"), &t); @@ -660,6 +677,8 @@ static int _php_ibase_bind_array(zval *val, char *buf, zend_ulong buf_size, /* { isc_encode_sql_date(&t, (ISC_DATE *) buf); break; case SQL_TYPE_TIME: + // TODO: + // case SQL_TIME_TZ: convert_to_string(val); #ifdef HAVE_STRPTIME strptime(Z_STRVAL_P(val), INI_STR("ibase.timeformat"), &t); @@ -714,6 +733,13 @@ static int _php_ibase_bind(XSQLDA *sqlda, zval *b_vars, BIND_BUF *buf, /* {{{ */ case SQL_TIMESTAMP: case SQL_TYPE_DATE: case SQL_TYPE_TIME: +#if FB_API_VER >= 40 + case SQL_INT128: + case SQL_DEC16: + case SQL_DEC34: + case SQL_TIMESTAMP_TZ: + case SQL_TIME_TZ: +#endif force_null = (Z_STRLEN_P(b_var) == 0); } @@ -737,6 +763,9 @@ static int _php_ibase_bind(XSQLDA *sqlda, zval *b_vars, BIND_BUF *buf, /* {{{ */ struct tm t; case SQL_TIMESTAMP: + // TODO: + // case SQL_TIMESTAMP_TZ: + // case SQL_TIME_TZ: case SQL_TYPE_DATE: case SQL_TYPE_TIME: if (Z_TYPE_P(b_var) == IS_LONG) { @@ -756,6 +785,8 @@ static int _php_ibase_bind(XSQLDA *sqlda, zval *b_vars, BIND_BUF *buf, /* {{{ */ format = INI_STR("ibase.dateformat"); break; case SQL_TYPE_TIME: + // TODO: + // case SQL_TIME_TZ: format = INI_STR("ibase.timeformat"); } if (!strptime(Z_STRVAL_P(b_var), format, &t)) { @@ -775,6 +806,8 @@ static int _php_ibase_bind(XSQLDA *sqlda, zval *b_vars, BIND_BUF *buf, /* {{{ */ isc_encode_sql_date(&t, &buf[i].val.dtval); break; case SQL_TYPE_TIME: + // TODO: + // case SQL_TIME_TZ: isc_encode_sql_time(&t, &buf[i].val.tmval); break; } @@ -954,8 +987,20 @@ static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */ case SQL_ARRAY: var->sqldata = emalloc(sizeof(ISC_QUAD)); break; +#if FB_API_VER >= 40 + // These are converted to VARCHAR via isc_dpb_set_bind tag at connect + // case SQL_DEC16: + // case SQL_DEC34: + // case SQL_INT128: + case SQL_TIMESTAMP_TZ: + var->sqldata = emalloc(sizeof(ISC_TIMESTAMP_TZ)); + break; + case SQL_TIME_TZ: + var->sqldata = emalloc(sizeof(ISC_TIME_TZ)); + break; +#endif default: - php_error(E_WARNING, "Unhandled sqltype: %d for sqlname %s %s:%d. This is most likely due to this PHP driver has been not kept up with newer server version", var->sqltype, var->sqlname, __FILE__, __LINE__); + php_error(E_WARNING, "Unhandled sqltype: %d for sqlname %s %s:%d", var->sqltype, var->sqlname, __FILE__, __LINE__); break; } /* switch */ @@ -1430,9 +1475,9 @@ static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ break; // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - case SQL_BOOLEAN: - ZVAL_BOOL(val, *(FB_BOOLEAN *) data); - break; + case SQL_BOOLEAN: + ZVAL_BOOL(val, *(FB_BOOLEAN *) data); + break; #endif case SQL_SHORT: n = *(short *) data; @@ -1483,6 +1528,44 @@ static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ case SQL_DOUBLE: ZVAL_DOUBLE(val, *(double *) data); break; +#if FB_API_VER >= 40 + // These are converted to VARCHAR via isc_dpb_set_bind tag at connect + // case SQL_DEC16: + // case SQL_DEC34: + // case SQL_INT128: + case SQL_TIME_TZ: + case SQL_TIMESTAMP_TZ: + char timeZoneBuffer[40] = {0}; + unsigned year, month, day, hours, minutes, seconds, fractions; + + if((type & ~1) == SQL_TIME_TZ){ + format = INI_STR("ibase.timeformat"); + fb_decode_time_tz((ISC_TIME_TZ *) data, &hours, &minutes, &seconds, &fractions, sizeof(timeZoneBuffer), timeZoneBuffer); + ISC_TIME time = fb_encode_time(hours, minutes, seconds, fractions); + isc_decode_sql_time(&time, &t); + } else { + format = INI_STR("ibase.timestampformat"); + fb_decode_timestamp_tz((ISC_TIMESTAMP_TZ *) data, &year, &month, &day, &hours, &minutes, &seconds, &fractions, sizeof(timeZoneBuffer), timeZoneBuffer); + ISC_TIMESTAMP ts; + ts.timestamp_date = fb_encode_date(year, month, day); + ts.timestamp_time = fb_encode_time(hours, minutes, seconds, fractions); + isc_decode_timestamp(&ts, &t); + } + + if (flag & PHP_IBASE_UNIXTIME) { + ZVAL_LONG(val, mktime(&t)); + } else { + char timeBuf[80] = {0}; + l = strftime(timeBuf, sizeof(timeBuf), format, &t); + if (l == 0) { + return FAILURE; + } + + size_t l = sprintf(string_data, "%s %s", timeBuf, timeZoneBuffer); + ZVAL_STRINGL(val, string_data, l); + } + break; +#endif case SQL_DATE: /* == case SQL_TIMESTAMP: */ format = INI_STR("ibase.timestampformat"); isc_decode_timestamp((ISC_TIMESTAMP *) data, &t); @@ -2040,9 +2123,9 @@ static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */ switch (var->sqltype & ~1) { // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - case SQL_BOOLEAN: - precision = 1; - break; + case SQL_BOOLEAN: + precision = 1; + break; #endif case SQL_SHORT: precision = 4; @@ -2070,9 +2153,9 @@ static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */ break; // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - case SQL_BOOLEAN: - s = "BOOLEAN"; - break; + case SQL_BOOLEAN: + s = "BOOLEAN"; + break; #endif case SQL_LONG: s = "INTEGER"; @@ -2105,6 +2188,18 @@ static void _php_ibase_field_info(zval *return_value, XSQLVAR *var) /* {{{ */ case SQL_QUAD: s = "QUAD"; break; +#if FB_API_VER >= 40 + // These are converted to VARCHAR via isc_dpb_set_bind tag at connect and will appear to clients as VARCHAR + // case SQL_DEC16: + // case SQL_DEC34: + // case SQL_INT128: + case SQL_TIMESTAMP_TZ: + s = "TIMESTAMP_TZ"; + break; + case SQL_TIME_TZ: + s = "TIME_TZ"; + break; +#endif } add_index_string(return_value, 4, s); add_assoc_string(return_value, "type", s); From a8cf7a6d202280ce5f9072436417a85433bd6d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sat, 1 Mar 2025 22:46:52 +0200 Subject: [PATCH 05/24] Instruct FB to convert INT128 and DECFLOAT to VARCHAR --- interbase.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interbase.c b/interbase.c index f34d59b..a9735a7 100644 --- a/interbase.c +++ b/interbase.c @@ -884,6 +884,13 @@ int _php_ibase_attach_db(char **args, size_t *len, zend_long *largs, isc_db_hand dpb += dpb_len; buf_len -= dpb_len; } + + // Do not handle directly INT128 or DECFLOAT, convert to VARCHAR at server instead + const char *compat = "int128 to varchar;decfloat to varchar"; + dpb_len = slprintf(dpb, buf_len, "%c%c%s", isc_dpb_set_bind, strlen(compat), compat); + dpb += dpb_len; + buf_len -= dpb_len; + if (isc_attach_database(IB_STATUS, (short)len[DB], args[DB], db, (short)(dpb-dpb_buffer), dpb_buffer)) { _php_ibase_error(); return FAILURE; From d1723b6064e963f55ca681fd481e44e273ad7d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sun, 2 Mar 2025 00:28:21 +0200 Subject: [PATCH 06/24] Add FB_API_VER guard --- interbase.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interbase.c b/interbase.c index a9735a7..de5c713 100644 --- a/interbase.c +++ b/interbase.c @@ -885,11 +885,13 @@ int _php_ibase_attach_db(char **args, size_t *len, zend_long *largs, isc_db_hand buf_len -= dpb_len; } +#if FB_API_VER >= 40 // Do not handle directly INT128 or DECFLOAT, convert to VARCHAR at server instead const char *compat = "int128 to varchar;decfloat to varchar"; dpb_len = slprintf(dpb, buf_len, "%c%c%s", isc_dpb_set_bind, strlen(compat), compat); dpb += dpb_len; buf_len -= dpb_len; +#endif if (isc_attach_database(IB_STATUS, (short)len[DB], args[DB], db, (short)(dpb-dpb_buffer), dpb_buffer)) { _php_ibase_error(); From 828ba1c454898ad552a385841a7b78d8151da6e8 Mon Sep 17 00:00:00 2001 From: Martins Lazdans Date: Sun, 2 Mar 2025 04:01:21 +0200 Subject: [PATCH 07/24] Add 8.4 --- win_build_scripts/php-fb-build-all.bat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win_build_scripts/php-fb-build-all.bat b/win_build_scripts/php-fb-build-all.bat index b84b8e5..c805f23 100644 --- a/win_build_scripts/php-fb-build-all.bat +++ b/win_build_scripts/php-fb-build-all.bat @@ -6,4 +6,5 @@ call php-fb-build.bat 8.0 vs16 || exit /B %ERRORLEVEL% call php-fb-build.bat 8.1 vs16 || exit /B %ERRORLEVEL% call php-fb-build.bat 8.2 vs16 || exit /B %ERRORLEVEL% call php-fb-build.bat 8.3 vs16 || exit /B %ERRORLEVEL% -call php-fb-build.bat master vs16 || exit /B %ERRORLEVEL% +call php-fb-build.bat 8.4 vs17 || exit /B %ERRORLEVEL% +call php-fb-build.bat master vs17 || exit /B %ERRORLEVEL% From 110c0f0e567231af6fac352d7fec2547eacfe4b1 Mon Sep 17 00:00:00 2001 From: Martins Lazdans Date: Sun, 2 Mar 2025 04:02:06 +0200 Subject: [PATCH 08/24] Add path for fbclient.dll --- win_build_scripts/php-fb-build.bat | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/win_build_scripts/php-fb-build.bat b/win_build_scripts/php-fb-build.bat index 41ac12c..ce9a696 100644 --- a/win_build_scripts/php-fb-build.bat +++ b/win_build_scripts/php-fb-build.bat @@ -57,10 +57,15 @@ set pfb_build_root=php%pfb_php_vers%\%pfb_cpp_vers%\ @REM check if ibase_connect() function exists in newly compiled extension set check_code="if(!function_exists('ibase_connect'))exit(1);" + +set TPATH=%PATH% +set PATH=%PFB_FB64_DIR%;%TPATH% "%pfb_build_root%x64\php-src\x64\Release_TS\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error "%pfb_build_root%x64\php-src\x64\Release\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error +set PATH=%PFB_FB32_DIR%;%TPATH% "%pfb_build_root%x86\php-src\Release_TS\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error "%pfb_build_root%x86\php-src\Release\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error +set PATH=%TPATH% call :log "PHP %pfb_php_vers% build OK" From 443e47da322e44ccdee81ec88be52f5c5c7e9fd5 Mon Sep 17 00:00:00 2001 From: Martins Lazdans Date: Sun, 2 Mar 2025 04:04:02 +0200 Subject: [PATCH 09/24] Add auto git hash + update lib path to FB5.0 --- win_build_scripts/php-fb-config.bat | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/win_build_scripts/php-fb-config.bat b/win_build_scripts/php-fb-config.bat index 0c8dd70..076ace2 100644 --- a/win_build_scripts/php-fb-config.bat +++ b/win_build_scripts/php-fb-config.bat @@ -2,15 +2,17 @@ @REM git command must be in PATH @REM +@REM php-firebird source directory +set PFB_SOURCE_DIR=D:\php-firebird\ + +for /f %%i in ('git -C %PFB_SOURCE_DIR%\php-firebird\ rev-parse --short HEAD') do set GIT_HASH=%%i + @REM sets php-firebird version part in extension file, for example, php_interbase-<<3.0.1-ba8e63b>>-7.3-vc15.dll -set PFB_VERS=3.0.1-ba8e63b +set PFB_VERS=3.0.1-%GIT_HASH% @REM Directory where all compiled files will be copied set PFB_OUTPUT_DIR=D:\php-firebird\releases\ @REM FB 32-bit and 64-bit libraries -set PFB_FB32_DIR=C:\Program Files\Firebird\Firebird_3_0-x86\ -set PFB_FB64_DIR=C:\Program Files\Firebird\Firebird_3_0\ - -@REM php-firebird source directory -set PFB_SOURCE_DIR=D:\php-firebird\ba8e63b\ +set PFB_FB32_DIR=C:\Program Files\Firebird\Firebird_5_0-x86 +set PFB_FB64_DIR=C:\Program Files\Firebird\Firebird_5_0 From 5ff80988cd1dec5c131cffdb11365a47f5478df2 Mon Sep 17 00:00:00 2001 From: Martins Lazdans Date: Sun, 2 Mar 2025 04:04:21 +0200 Subject: [PATCH 10/24] Cleanup FB paths --- config.w32 | 12 ++++++------ win_build_scripts/php-fb-sdk-build.bat | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/config.w32 b/config.w32 index 0cca7e7..883e189 100644 --- a/config.w32 +++ b/config.w32 @@ -3,12 +3,12 @@ ARG_WITH("interbase", "InterBase support", "no"); if (PHP_INTERBASE != "no") { - - if (CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_INTERBASE", - PHP_PHP_BUILD + "\\include\\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))) { - + if ( + CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_INTERBASE", PHP_INTERBASE + "\\include") && ( + CHECK_LIB("fbclient_ms.lib", "interbase", PHP_INTERBASE + "\\lib") || + CHECK_LIB("gds32_ms.lib", "interbase", PHP_INTERBASE + "\\lib") + ) + ) { EXTENSION("interbase", "interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c pdo_firebird_utils.cpp", PHP_INTERBASE_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE('HAVE_IBASE', 1, 'Have interbase library'); } else { diff --git a/win_build_scripts/php-fb-sdk-build.bat b/win_build_scripts/php-fb-sdk-build.bat index 6b4c1ef..ef629b5 100644 --- a/win_build_scripts/php-fb-sdk-build.bat +++ b/win_build_scripts/php-fb-sdk-build.bat @@ -41,10 +41,10 @@ exit /B ) if "%pfb_x86%" gtr "0" ( - set with_interbase="shared,%PFB_FB32_DIR%lib;%PFB_FB32_DIR%include" + set with_interbase="shared,%PFB_FB32_DIR%" set build_msg=%build_msg% x86 ) else ( - set with_interbase="shared,%PFB_FB64_DIR%lib;%PFB_FB64_DIR%include" + set with_interbase="shared,%PFB_FB64_DIR%" set build_msg=%build_msg% x86_64 ) From e6ff7cc6689ab6710ccaf7f12551de95de2c78d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sun, 2 Mar 2025 22:32:09 +0200 Subject: [PATCH 11/24] Tidy up --- win_build_scripts/README.md | 2 +- win_build_scripts/php-fb-build.bat | 4 ++-- win_build_scripts/php-fb-config.bat | 4 ++-- win_build_scripts/php-fb-sdk-build.bat | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/win_build_scripts/README.md b/win_build_scripts/README.md index 5253401..807d158 100644 --- a/win_build_scripts/README.md +++ b/win_build_scripts/README.md @@ -12,7 +12,7 @@ Make sure you got ~20GB free disk space to build for all PHP versions. Make sure ``git`` is in you PATH -1. Set up Microsoft Visual Studio vc15 and vs16. +1. Set up Microsoft Visual Studio vc15, vs16 and vs17 (for PHP8.4+). 2. Set up Firebird 32-bit and 64-bit installations or libraries. 3. Set up PHP-SDK according to https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 4. Clone php-firebird extension source somewhere. diff --git a/win_build_scripts/php-fb-build.bat b/win_build_scripts/php-fb-build.bat index ce9a696..accc387 100644 --- a/win_build_scripts/php-fb-build.bat +++ b/win_build_scripts/php-fb-build.bat @@ -59,10 +59,10 @@ set pfb_build_root=php%pfb_php_vers%\%pfb_cpp_vers%\ set check_code="if(!function_exists('ibase_connect'))exit(1);" set TPATH=%PATH% -set PATH=%PFB_FB64_DIR%;%TPATH% +set PATH=%FB64_DIR%;%TPATH% "%pfb_build_root%x64\php-src\x64\Release_TS\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error "%pfb_build_root%x64\php-src\x64\Release\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error -set PATH=%PFB_FB32_DIR%;%TPATH% +set PATH=%FB32_DIR%;%TPATH% "%pfb_build_root%x86\php-src\Release_TS\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error "%pfb_build_root%x86\php-src\Release\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error set PATH=%TPATH% diff --git a/win_build_scripts/php-fb-config.bat b/win_build_scripts/php-fb-config.bat index 076ace2..c194371 100644 --- a/win_build_scripts/php-fb-config.bat +++ b/win_build_scripts/php-fb-config.bat @@ -14,5 +14,5 @@ set PFB_VERS=3.0.1-%GIT_HASH% set PFB_OUTPUT_DIR=D:\php-firebird\releases\ @REM FB 32-bit and 64-bit libraries -set PFB_FB32_DIR=C:\Program Files\Firebird\Firebird_5_0-x86 -set PFB_FB64_DIR=C:\Program Files\Firebird\Firebird_5_0 +set FB32_DIR=C:\Program Files\Firebird\Firebird_5_0-x86 +set FB64_DIR=C:\Program Files\Firebird\Firebird_5_0 diff --git a/win_build_scripts/php-fb-sdk-build.bat b/win_build_scripts/php-fb-sdk-build.bat index ef629b5..61c2b73 100644 --- a/win_build_scripts/php-fb-sdk-build.bat +++ b/win_build_scripts/php-fb-sdk-build.bat @@ -3,13 +3,13 @@ @REM Must be called under phpsdk--.bat @REM @REM Calling script should set variables: -@REM [pfb_nts] [pfb_x86] +@REM [pfb_nts] [pfb_x86] @REM @REM set pfb_php_vers=7.4 @REM set pfb_nts=1 if nts expected, 0 if ts @REM set pfb_x86=1 if linking to x86 fbclient, o if x64 @REM -@REM all set in php-fb-config.bat +@REM all set in php-fb-config.bat @REM goto :MAIN @@ -41,10 +41,10 @@ exit /B ) if "%pfb_x86%" gtr "0" ( - set with_interbase="shared,%PFB_FB32_DIR%" + set with_interbase="shared,%FB32_DIR%" set build_msg=%build_msg% x86 ) else ( - set with_interbase="shared,%PFB_FB64_DIR%" + set with_interbase="shared,%FB64_DIR%" set build_msg=%build_msg% x86_64 ) From fe5a7d66ceb00e0bcc30701e53744ff2b48cd84d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Sun, 2 Mar 2025 22:49:09 +0200 Subject: [PATCH 12/24] Whitespace mess --- ibase_query.c | 12 ++++++------ interbase.c | 6 +++--- php_ibase_includes.h | 43 +++++++++++++++++++++---------------------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/ibase_query.c b/ibase_query.c index 5e7ca94..2ceb8c9 100644 --- a/ibase_query.c +++ b/ibase_query.c @@ -39,14 +39,14 @@ #include "php_ibase_includes.h" #include "pdo_firebird_utils.h" -#define ISC_LONG_MIN INT_MIN -#define ISC_LONG_MAX INT_MAX +#define ISC_LONG_MIN INT_MIN +#define ISC_LONG_MAX INT_MAX -#define QUERY_RESULT 1 -#define EXECUTE_RESULT 2 +#define QUERY_RESULT 1 +#define EXECUTE_RESULT 2 -#define FETCH_ROW 1 -#define FETCH_ARRAY 2 +#define FETCH_ROW 1 +#define FETCH_ARRAY 2 typedef struct { ISC_ARRAY_DESC ar_desc; diff --git a/interbase.c b/interbase.c index de5c713..78800b7 100644 --- a/interbase.c +++ b/interbase.c @@ -45,9 +45,9 @@ #include -#define ROLLBACK 0 -#define COMMIT 1 -#define RETAIN 2 +#define ROLLBACK 0 +#define COMMIT 1 +#define RETAIN 2 #define CHECK_LINK(link) { if (link==NULL) { php_error_docref(NULL, E_WARNING, "A link to the server could not be established"); RETURN_FALSE; } } diff --git a/php_ibase_includes.h b/php_ibase_includes.h index b55fee6..3e0cda8 100644 --- a/php_ibase_includes.h +++ b/php_ibase_includes.h @@ -112,25 +112,25 @@ typedef struct event { } ibase_event; enum php_interbase_option { - PHP_IBASE_DEFAULT = 0, - PHP_IBASE_CREATE = 0, + PHP_IBASE_DEFAULT = 0, + PHP_IBASE_CREATE = 0, /* fetch flags */ - PHP_IBASE_FETCH_BLOBS = 1, - PHP_IBASE_FETCH_ARRAYS = 2, - PHP_IBASE_UNIXTIME = 4, + PHP_IBASE_FETCH_BLOBS = 1, + PHP_IBASE_FETCH_ARRAYS = 2, + PHP_IBASE_UNIXTIME = 4, /* transaction access mode */ - PHP_IBASE_WRITE = 1, - PHP_IBASE_READ = 2, + PHP_IBASE_WRITE = 1, + PHP_IBASE_READ = 2, /* transaction isolation level */ - PHP_IBASE_CONCURRENCY = 4, - PHP_IBASE_COMMITTED = 8, - PHP_IBASE_REC_NO_VERSION = 32, - PHP_IBASE_REC_VERSION = 64, - PHP_IBASE_CONSISTENCY = 16, + PHP_IBASE_CONCURRENCY = 4, + PHP_IBASE_COMMITTED = 8, + PHP_IBASE_REC_NO_VERSION = 32, + PHP_IBASE_REC_VERSION = 64, + PHP_IBASE_CONSISTENCY = 16, /* transaction lock resolution */ - PHP_IBASE_WAIT = 128, - PHP_IBASE_NOWAIT = 256, - PHP_IBASE_LOCK_TIMEOUT = 512, + PHP_IBASE_WAIT = 128, + PHP_IBASE_NOWAIT = 256, + PHP_IBASE_LOCK_TIMEOUT = 512, }; #define IBG(v) ZEND_MODULE_GLOBALS_ACCESSOR(ibase, v) @@ -139,12 +139,11 @@ enum php_interbase_option { ZEND_TSRMLS_CACHE_EXTERN() #endif -#define BLOB_ID_LEN 18 -#define BLOB_ID_MASK "0x%" LL_MASK "x" - -#define BLOB_INPUT 1 -#define BLOB_OUTPUT 2 +#define BLOB_ID_LEN 18 +#define BLOB_ID_MASK "0x%" LL_MASK "x" +#define BLOB_INPUT 1 +#define BLOB_OUTPUT 2 #ifdef PHP_WIN32 // Case switch, because of troubles on Windows and PHP 8.0 @@ -166,11 +165,11 @@ void _php_ibase_module_error(char *, ...) PHP_ATTRIBUTE_FORMAT(printf,1,2); /* determine if a resource is a link or transaction handle */ -#define PHP_IBASE_LINK_TRANS(zv, lh, th) \ +#define PHP_IBASE_LINK_TRANS(zv, lh, th) \ do { \ if (!zv) { \ lh = (ibase_db_link *)zend_fetch_resource2( \ - IBG(default_link), "InterBase link", le_link, le_plink); \ + IBG(default_link), "InterBase link", le_link, le_plink); \ } else { \ _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, zv, &lh, &th); \ } \ From 67438b05cea464b107b54e013a4a5afa7c722a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Mon, 3 Mar 2025 00:27:37 +0200 Subject: [PATCH 13/24] Whitespace mess --- ibase_query.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/ibase_query.c b/ibase_query.c index 2ceb8c9..8a503df 100644 --- a/ibase_query.c +++ b/ibase_query.c @@ -97,7 +97,7 @@ typedef struct { union { // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN - FB_BOOLEAN bval; + FB_BOOLEAN bval; #endif short sval; float fval; @@ -221,9 +221,9 @@ void php_ibase_query_minit(INIT_FUNC_ARGS) /* {{{ */ le_statement = zend_register_list_destructors_ex(_php_ibase_free_statement, NULL, "interbase statement", module_number); le_result = zend_register_list_destructors_ex(_php_ibase_free_result, NULL, - "interbase result", module_number); + "interbase result", module_number); le_query = zend_register_list_destructors_ex(php_ibase_free_query_rsrc, NULL, - "interbase query", module_number); + "interbase query", module_number); } /* }}} */ @@ -1231,7 +1231,7 @@ PHP_FUNCTION(ibase_query) zend_long l; default: - if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3, "rrs", + if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3, "rrs", &zlink, &ztrans, &query, &query_len)) { ib_link = (ibase_db_link*)zend_fetch_resource2_ex(zlink, LE_LINK, le_link, le_plink); @@ -1240,7 +1240,7 @@ PHP_FUNCTION(ibase_query) trans_res = Z_RES_P(ztrans); bind_i = 3; break; - } + } case 2: if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2, "rs", &zlink, &query, &query_len)) { @@ -1308,7 +1308,7 @@ PHP_FUNCTION(ibase_query) do { int bind_n = ZEND_NUM_ARGS() - bind_i, - expected_n = ib_query.in_sqlda ? ib_query.in_sqlda->sqld : 0; + expected_n = ib_query.in_sqlda ? ib_query.in_sqlda->sqld : 0; if (bind_n != expected_n) { php_error_docref(NULL, (bind_n < expected_n) ? E_WARNING : E_NOTICE, @@ -1898,11 +1898,11 @@ PHP_FUNCTION(ibase_free_result) ib_result = (ibase_result *)zend_fetch_resource_ex(result_arg, LE_RESULT, le_result); zend_list_delete(Z_RES_P(result_arg)); - /* - * Bugfix of issue #40 - * Reset pointer after freeing to NULL - */ - Z_RES_P(result_arg)->ptr = NULL; + /* + * Bugfix of issue #40 + * Reset pointer after freeing to NULL + */ + Z_RES_P(result_arg)->ptr = NULL; RETURN_TRUE; } @@ -2005,9 +2005,8 @@ PHP_FUNCTION(ibase_execute) ib_query->result_res = NULL; } - if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, ib_query, - args)) { - break; + if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, ib_query, args)) { + break; } /* free the query if trans handle was released */ From 81aa3c21cbda7c4e3b771bb0d8c71af5fc37048b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Mon, 3 Mar 2025 04:03:58 +0200 Subject: [PATCH 14/24] Arguments to ibase_trans() all are variadic --- interbase.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interbase.c b/interbase.c index 78800b7..6e70bd9 100644 --- a/interbase.c +++ b/interbase.c @@ -90,8 +90,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_drop_db, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_trans, 0, 0, 0) - ZEND_ARG_INFO(0, link_identifier) - ZEND_ARG_INFO(0, trans_args) + ZEND_ARG_VARIADIC_INFO(0, trans_args) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_commit, 0, 0, 0) From 702477cd80d5711a4710576abda8ec6a37d9d0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Mon, 3 Mar 2025 15:29:23 +0200 Subject: [PATCH 15/24] Add optional hosts parameter --- tests/config.inc | 1 + tests/ibase_drop_db_001.phpt | 2 +- tests/ibase_drop_db_003.phpt | 1 + tests/ibase_drop_db_004.phpt | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/config.inc b/tests/config.inc index 3cbe601..622d196 100644 --- a/tests/config.inc +++ b/tests/config.inc @@ -2,5 +2,6 @@ $user = 'SYSDBA'; $password = 'masterkey'; +$host = ""; ini_set('ibase.default_user',$user); ini_set('ibase.default_password',$password); diff --git a/tests/ibase_drop_db_001.phpt b/tests/ibase_drop_db_001.phpt index bdad766..64efeae 100644 --- a/tests/ibase_drop_db_001.phpt +++ b/tests/ibase_drop_db_001.phpt @@ -8,7 +8,7 @@ ibase_drop_db(): Basic test require("config.inc"); unlink($file = tempnam('/tmp',"php_ibase_test")); - +if(!empty($host))$file = "$host:$file"; $db = ibase_query(IBASE_CREATE, sprintf("CREATE SCHEMA '%s' USER '%s' PASSWORD '%s' DEFAULT CHARACTER SET %s",$file, diff --git a/tests/ibase_drop_db_003.phpt b/tests/ibase_drop_db_003.phpt index a2f2d38..1269412 100644 --- a/tests/ibase_drop_db_003.phpt +++ b/tests/ibase_drop_db_003.phpt @@ -11,6 +11,7 @@ include("skipif-php7-or-older.inc"); require("config.inc"); unlink($file = tempnam('/tmp',"php_ibase_test")); +if(!empty($host))$file = "$host:$file"; $db = ibase_query(IBASE_CREATE, sprintf("CREATE SCHEMA '%s' USER '%s' PASSWORD '%s' DEFAULT CHARACTER SET %s",$file, diff --git a/tests/ibase_drop_db_004.phpt b/tests/ibase_drop_db_004.phpt index adc4923..b91202f 100644 --- a/tests/ibase_drop_db_004.phpt +++ b/tests/ibase_drop_db_004.phpt @@ -11,6 +11,7 @@ include("skipif-php7-or-older.inc"); require("config.inc"); unlink($file = tempnam('/tmp',"php_ibase_test")); +if(!empty($host))$file = "$host:$file"; $db = ibase_query(IBASE_CREATE, sprintf("CREATE SCHEMA '%s' USER '%s' PASSWORD '%s' DEFAULT CHARACTER SET %s",$file, From 67834017b99ee29912697d2d40330543c1824b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Mon, 3 Mar 2025 15:30:30 +0200 Subject: [PATCH 16/24] Trim error message Some PHP versions return error "bool given" but some, for example, PHP8.4 returns "false given". Trim that message a bit --- tests/ibase_num_params_004.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ibase_num_params_004.phpt b/tests/ibase_num_params_004.phpt index daaf849..83f8db4 100644 --- a/tests/ibase_num_params_004.phpt +++ b/tests/ibase_num_params_004.phpt @@ -24,4 +24,4 @@ int(2) Warning: ibase_prepare(): Dynamic SQL Error SQL error code = -%d Column unknown X At line %d, column %d %s -Fatal error: Uncaught TypeError: ibase_num_params(): Argument #1 ($query) must be of type resource, bool given in %a \ No newline at end of file +Fatal error: Uncaught TypeError: ibase_num_params(): Argument #1 ($query) must be of type resource, %a \ No newline at end of file From c6d6f600f7d0af20fbff774b84fac8e0bed47d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Mon, 3 Mar 2025 15:30:45 +0200 Subject: [PATCH 17/24] Add optional hosts parameter --- tests/interbase.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/interbase.inc b/tests/interbase.inc index 9b47417..254dab9 100644 --- a/tests/interbase.inc +++ b/tests/interbase.inc @@ -5,6 +5,7 @@ require('functions.inc'); /* we need just the generated name, not the file itself */ unlink($test_base = tempnam(sys_get_temp_dir(),"php_ibase_test")); +if(!empty($host))$test_base = "$host:$test_base"; function init_db() { @@ -31,5 +32,3 @@ function cleanup_db() register_shutdown_function('cleanup_db'); init_db(); - -?> From e297ad3d1159f009f948f6135125827ccd64ee0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 03:48:22 +0200 Subject: [PATCH 18/24] Whitespace mess --- ibase_query.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ibase_query.c b/ibase_query.c index 8a503df..a5deb34 100644 --- a/ibase_query.c +++ b/ibase_query.c @@ -956,8 +956,8 @@ static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */ // Boolean data type exists since FB 3.0 #ifdef SQL_BOOLEAN case SQL_BOOLEAN: - var->sqldata = emalloc(sizeof(FB_BOOLEAN)); - break; + var->sqldata = emalloc(sizeof(FB_BOOLEAN)); + break; #endif case SQL_SHORT: var->sqldata = emalloc(sizeof(short)); From d39215a2113f86e72df4e4ae6b0970148f2aafe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 04:09:29 +0200 Subject: [PATCH 19/24] Fix segfault when inserting null (tests/003.phpt) 003.phpt segfaulted at null insert on PHP8.4. More testing needed with different PHP versions --- ibase_query.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ibase_query.c b/ibase_query.c index a5deb34..2e07a94 100644 --- a/ibase_query.c +++ b/ibase_query.c @@ -747,6 +747,7 @@ static int _php_ibase_bind(XSQLDA *sqlda, zval *b_vars, BIND_BUF *buf, /* {{{ */ case IS_NULL: buf[i].sqlind = -1; + sqlda->sqlvar->sqldata = NULL; if (var->sqltype & SQL_ARRAY) ++array_cnt; From 8795635540c23ba17f1e1ad035e1eb8b6244f127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 04:10:10 +0200 Subject: [PATCH 20/24] Add file to IBDEBUG output --- php_ibase_includes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_ibase_includes.h b/php_ibase_includes.h index 3e0cda8..eaf988e 100644 --- a/php_ibase_includes.h +++ b/php_ibase_includes.h @@ -41,7 +41,7 @@ #define IB_STATUS (IBG(status)) #ifdef IBASE_DEBUG -#define IBDEBUG(a) php_printf("::: %s (%d)\n", a, __LINE__); +#define IBDEBUG(a) php_printf("::: %s (%s:%d)\n", a, __FILE__, __LINE__); #endif #ifndef IBDEBUG From 6c1ad7ae842fe55023e5279152c0e02addcdc4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 11:50:59 +0200 Subject: [PATCH 21/24] Process transaction parameters in separate function --- interbase.c | 89 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/interbase.c b/interbase.c index 6e70bd9..9e9ecf9 100644 --- a/interbase.c +++ b/interbase.c @@ -1141,6 +1141,54 @@ PHP_FUNCTION(ibase_drop_db) #define TPB_MAX_SIZE (8*sizeof(char)) +void _php_ibase_populate_trans(zend_long trans_argl, zend_long trans_timeout, char *last_tpb, unsigned short *len) /* {{{ */ +{ + unsigned short tpb_len = 0; + if (trans_argl != PHP_IBASE_DEFAULT) { + last_tpb[tpb_len++] = isc_tpb_version3; + + /* access mode */ + if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) { + last_tpb[tpb_len++] = isc_tpb_read; + } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) { + last_tpb[tpb_len++] = isc_tpb_write; + } + + /* isolation level */ + if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) { + last_tpb[tpb_len++] = isc_tpb_read_committed; + if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) { + last_tpb[tpb_len++] = isc_tpb_rec_version; + } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) { + last_tpb[tpb_len++] = isc_tpb_no_rec_version; + } + } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) { + last_tpb[tpb_len++] = isc_tpb_consistency; + } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) { + last_tpb[tpb_len++] = isc_tpb_concurrency; + } + + /* lock resolution */ + if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) { + last_tpb[tpb_len++] = isc_tpb_nowait; + } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) { + last_tpb[tpb_len++] = isc_tpb_wait; + if (PHP_IBASE_LOCK_TIMEOUT == (trans_argl & PHP_IBASE_LOCK_TIMEOUT)) { + if (trans_timeout <= 0 || trans_timeout > 0x7FFF) { + php_error_docref(NULL, E_WARNING, "Invalid timeout parameter"); + } else { + last_tpb[tpb_len++] = isc_tpb_lock_timeout; + last_tpb[tpb_len++] = sizeof(ISC_SHORT); + last_tpb[tpb_len] = (ISC_SHORT)trans_timeout; + tpb_len += sizeof(ISC_SHORT); + } + } + } + } + *len = tpb_len; +} +/* }}} */ + PHP_FUNCTION(ibase_trans) { unsigned short i, link_cnt = 0, tpb_len = 0; @@ -1200,55 +1248,20 @@ PHP_FUNCTION(ibase_trans) convert_to_long_ex(&args[i]); trans_argl = Z_LVAL(args[i]); - if (trans_argl != PHP_IBASE_DEFAULT) { - last_tpb[tpb_len++] = isc_tpb_version3; - - /* access mode */ - if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) { - last_tpb[tpb_len++] = isc_tpb_read; - } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) { - last_tpb[tpb_len++] = isc_tpb_write; - } - - /* isolation level */ - if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) { - last_tpb[tpb_len++] = isc_tpb_read_committed; - if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) { - last_tpb[tpb_len++] = isc_tpb_rec_version; - } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) { - last_tpb[tpb_len++] = isc_tpb_no_rec_version; - } - } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) { - last_tpb[tpb_len++] = isc_tpb_consistency; - } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) { - last_tpb[tpb_len++] = isc_tpb_concurrency; - } - - /* lock resolution */ - if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) { - last_tpb[tpb_len++] = isc_tpb_nowait; - } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) { - last_tpb[tpb_len++] = isc_tpb_wait; + // Skip conflicting parameters + if (PHP_IBASE_NOWAIT != (trans_argl & PHP_IBASE_NOWAIT) && PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) { if (PHP_IBASE_LOCK_TIMEOUT == (trans_argl & PHP_IBASE_LOCK_TIMEOUT)) { if((i + 1 < argn) && (Z_TYPE(args[i + 1]) == IS_LONG)){ i++; convert_to_long_ex(&args[i]); trans_timeout = Z_LVAL(args[i]); - - if (trans_timeout <= 0 || trans_timeout > 0x7FFF) { - php_error_docref(NULL, E_WARNING, "Invalid timeout parameter"); - } else { - last_tpb[tpb_len++] = isc_tpb_lock_timeout; - last_tpb[tpb_len++] = sizeof(ISC_SHORT); - last_tpb[tpb_len] = (ISC_SHORT)trans_timeout; - tpb_len += sizeof(ISC_SHORT); - } } else { php_error_docref(NULL, E_WARNING, "IBASE_LOCK_TIMEOUT expects next argument to be timeout value"); } } } + _php_ibase_populate_trans(trans_argl, trans_timeout, last_tpb, &tpb_len); } } } From 9651d2da0de43ea0f259a7bd8de938af6486065b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 11:51:33 +0200 Subject: [PATCH 22/24] Introduce ibase.default_trans_params and printer --- interbase.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ php_ibase_includes.h | 1 + 2 files changed, 63 insertions(+) diff --git a/interbase.c b/interbase.c index 9e9ecf9..2f1ba2c 100644 --- a/interbase.c +++ b/interbase.c @@ -706,6 +706,67 @@ static PHP_INI_DISP(php_ibase_password_displayer_cb) } } +#define PUTS_TP(str) do { \ + if(has_puts) { \ + PUTS(" | "); \ + } \ + PUTS(str); \ + has_puts = true; \ +} while (0) + +static PHP_INI_DISP(php_ibase_trans_displayer) +{ + bool has_puts = false; + char *value; + + if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { + value = ZSTR_VAL(ini_entry->orig_value); + } else if (ini_entry->value) { + value = ZSTR_VAL(ini_entry->value); + } else { + value = NULL; + } + + if (value) { + zend_long trans_argl = atol(value); + + if (trans_argl != PHP_IBASE_DEFAULT) { + /* access mode */ + if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) { + PUTS_TP("IBASE_READ"); + } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) { + PUTS_TP("IBASE_WRITE"); + } + + /* isolation level */ + if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) { + PUTS_TP("IBASE_COMMITTED"); + if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) { + PUTS_TP("IBASE_REC_VERSION"); + } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) { + PUTS_TP("IBASE_REC_NO_VERSION"); + } + } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) { + PUTS_TP("IBASE_CONSISTENCY"); + } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) { + PUTS_TP("IBASE_CONCURRENCY"); + } + + /* lock resolution */ + if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) { + PUTS_TP("IBASE_NOWAIT"); + } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) { + PUTS_TP("IBASE_WAIT"); + if (PHP_IBASE_LOCK_TIMEOUT == (trans_argl & PHP_IBASE_LOCK_TIMEOUT)) { + PUTS_TP("IBASE_LOCK_TIMEOUT"); + } + } + } else { + PUTS_TP("IBASE_DEFAULT"); + } + } +} + /* {{{ startup, shutdown and info functions */ PHP_INI_BEGIN() PHP_INI_ENTRY_EX("ibase.allow_persistent", "1", PHP_INI_SYSTEM, NULL, zend_ini_boolean_displayer_cb) @@ -718,6 +779,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("ibase.timestampformat", IB_DEF_DATE_FMT " " IB_DEF_TIME_FMT, PHP_INI_ALL, NULL) PHP_INI_ENTRY("ibase.dateformat", IB_DEF_DATE_FMT, PHP_INI_ALL, NULL) PHP_INI_ENTRY("ibase.timeformat", IB_DEF_TIME_FMT, PHP_INI_ALL, NULL) + STD_PHP_INI_ENTRY_EX("ibase.default_trans_params", "0", PHP_INI_ALL, OnUpdateLongGEZero, default_trans_params, zend_ibase_globals, ibase_globals, php_ibase_trans_displayer) PHP_INI_END() static PHP_GINIT_FUNCTION(ibase) diff --git a/php_ibase_includes.h b/php_ibase_includes.h index eaf988e..5136fcb 100644 --- a/php_ibase_includes.h +++ b/php_ibase_includes.h @@ -69,6 +69,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ibase) zend_long num_links, num_persistent; char errmsg[MAX_ERRMSG]; zend_long sql_code; + zend_long default_trans_params; ZEND_END_MODULE_GLOBALS(ibase) ZEND_EXTERN_MODULE_GLOBALS(ibase) From fec3f352445b07f8c27cc61e21dea0c210511657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 12:13:49 +0200 Subject: [PATCH 23/24] Introduce ibase.default_lock_timeout INI setting --- interbase.c | 1 + php_ibase_includes.h | 1 + 2 files changed, 2 insertions(+) diff --git a/interbase.c b/interbase.c index 2f1ba2c..03b54b9 100644 --- a/interbase.c +++ b/interbase.c @@ -780,6 +780,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("ibase.dateformat", IB_DEF_DATE_FMT, PHP_INI_ALL, NULL) PHP_INI_ENTRY("ibase.timeformat", IB_DEF_TIME_FMT, PHP_INI_ALL, NULL) STD_PHP_INI_ENTRY_EX("ibase.default_trans_params", "0", PHP_INI_ALL, OnUpdateLongGEZero, default_trans_params, zend_ibase_globals, ibase_globals, php_ibase_trans_displayer) + STD_PHP_INI_ENTRY_EX("ibase.default_lock_timeout", "0", PHP_INI_ALL, OnUpdateLongGEZero, default_lock_timeout, zend_ibase_globals, ibase_globals, display_link_numbers) PHP_INI_END() static PHP_GINIT_FUNCTION(ibase) diff --git a/php_ibase_includes.h b/php_ibase_includes.h index 5136fcb..f162310 100644 --- a/php_ibase_includes.h +++ b/php_ibase_includes.h @@ -70,6 +70,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ibase) char errmsg[MAX_ERRMSG]; zend_long sql_code; zend_long default_trans_params; + zend_long default_lock_timeout; // only used togetger with trans_param IBASE_LOCK_TIMEOUT ZEND_END_MODULE_GLOBALS(ibase) ZEND_EXTERN_MODULE_GLOBALS(ibase) From c185385de8c5340f90cee2a18771766a974226f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Lazd=C4=81ns?= Date: Tue, 4 Mar 2025 12:24:06 +0200 Subject: [PATCH 24/24] Start default transaction according to INI settings --- interbase.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/interbase.c b/interbase.c index 03b54b9..3d93ac0 100644 --- a/interbase.c +++ b/interbase.c @@ -1407,7 +1407,20 @@ int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans) /* {{{ */ ib_link->tr_list->trans = tr; } if (tr->handle == 0) { - if (isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL)) { + ISC_STATUS result; + zend_long trans_argl = IBG(default_trans_params); + + if(trans_argl == PHP_IBASE_DEFAULT){ + result = isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL); + } else { + zend_long trans_timeout = IBG(default_lock_timeout); + char last_tpb[TPB_MAX_SIZE]; + unsigned short tpb_len = 0; + _php_ibase_populate_trans(trans_argl, trans_timeout, last_tpb, &tpb_len); + result = isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, tpb_len, last_tpb); + } + + if (result) { _php_ibase_error(); return FAILURE; }