diff --git a/NEWS b/NEWS index c0f63de1bdf4e..783156f9970ed 100644 --- a/NEWS +++ b/NEWS @@ -35,6 +35,7 @@ PHP NEWS . Added Pdo\Firebird::ATTR_API_VERSION. (SakiTakamachi) . Added getApiVersion() and removed from getAttribute(). (SakiTakamachi) + . Supported Firebird 4.0 datatypes. (sim1984) - PGSQL: . pg_convert/pg_insert/pg_update/pg_delete ; regexes are now cached. diff --git a/UPGRADING b/UPGRADING index beef5bbbcc76f..153abf0ed744e 100644 --- a/UPGRADING +++ b/UPGRADING @@ -524,6 +524,8 @@ PHP 8.4 UPGRADE NOTES . The content that is built changes depending on the value of FB_API_VER in ibase.h, so added static method Pdo\Firebird::getApiVersion() to obtain that value. This value can also be referenced from phpinfo. + . Five new data types are now available: INT128, DEC16, DEC34, TIMESTAMP_TZ, TIME_TZ. + These are available starting with Firebird 4.0. - PDO_MYSQL: . getAttribute, enabled to get the value of ATTR_FETCH_TABLE_NAMES. diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 725987531906a..ddb7db9b15b2b 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -460,6 +460,56 @@ static int php_firebird_preprocess(const zend_string* sql, char* sql_out, HashTa return 1; } +#if FB_API_VER >= 40 +/* set coercing a data type */ +static void set_coercing_data_type(XSQLDA* sqlda) +{ + /* Data types introduced in Firebird 4.0 are difficult to process using the Firebird Legacy API. */ + /* These data types include DECFLOAT(16), DECFLOAT(34), INT128 (NUMERIC/DECIMAL(38, x)), */ + /* TIMESTAMP WITH TIME ZONE, and TIME WITH TIME ZONE. In any case, at least the first three data types */ + /* can only be mapped to strings. The last two too, but for them it is potentially possible to set */ + /* the display format, as is done for TIMESTAMP. This function allows you to ensure minimal performance */ + /* of queries if they contain columns and parameters of the above types. */ + unsigned int i; + short dtype; + short nullable; + XSQLVAR* var; + for (i=0, var = sqlda->sqlvar; i < sqlda->sqld; i++, var++) { + dtype = (var->sqltype & ~1); /* drop flag bit */ + nullable = (var->sqltype & 1); + switch(dtype) { + case SQL_INT128: + var->sqltype = SQL_VARYING + nullable; + var->sqllen = 46; + var->sqlscale = 0; + break; + + case SQL_DEC16: + var->sqltype = SQL_VARYING + nullable; + var->sqllen = 24; + break; + + case SQL_DEC34: + var->sqltype = SQL_VARYING + nullable; + var->sqllen = 43; + break; + + case SQL_TIMESTAMP_TZ: + var->sqltype = SQL_VARYING + nullable; + var->sqllen = 58; + break; + + case SQL_TIME_TZ: + var->sqltype = SQL_VARYING + nullable; + var->sqllen = 46; + break; + default: + break; + } + } +} +#endif + /* map driver specific error message to PDO error */ void php_firebird_set_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *state, const size_t state_len, const char *msg, const size_t msg_len) /* {{{ */ @@ -605,6 +655,11 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */ break; } +#if FB_API_VER >= 40 + /* set coercing a data type */ + set_coercing_data_type(&S->out_sqlda); +#endif + /* allocate the input descriptors */ if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &num_sqlda)) { break; @@ -618,6 +673,11 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */ if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, S->in_sqlda)) { break; } + +#if FB_API_VER >= 40 + /* set coercing a data type */ + set_coercing_data_type(S->in_sqlda); +#endif } stmt->driver_data = S; diff --git a/ext/pdo_firebird/tests/fb4_datatypes.phpt b/ext/pdo_firebird/tests/fb4_datatypes.phpt new file mode 100644 index 0000000000000..3ae452d5eb4e4 --- /dev/null +++ b/ext/pdo_firebird/tests/fb4_datatypes.phpt @@ -0,0 +1,56 @@ +--TEST-- +PDO_Firebird: Supported Firebird 4.0 datatypes +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--XLEAK-- +A bug in firebird causes a memory leak when calling `isc_attach_database()`. +See https://github.com/FirebirdSQL/firebird/issues/7849 +--FILE-- +prepare($sql); +$stmt->execute(); +$data = $stmt->fetch(\PDO::FETCH_ASSOC); +$stmt->closeCursor(); +$str = json_encode($data, JSON_PRETTY_PRINT); +echo $str; +echo "\ndone\n"; +?> +--EXPECTF-- +{ + "I64": 15, + "I128": "15", + "N": "123.97", + "N2": "123.97", + "TS": "2024-05-04 12:59:34", + "TS_TZ": "%s 12:59:34.2390 Europe\/Moscow", + "T": "12:59:34", + "T_TZ": "12:59:34.2390 Europe\/Moscow", + "DF16": "1.128", + "DF34": "1.128" +} +done diff --git a/ext/pdo_firebird/tests/fb4_datatypes_params.phpt b/ext/pdo_firebird/tests/fb4_datatypes_params.phpt new file mode 100644 index 0000000000000..f1b4827b9e724 --- /dev/null +++ b/ext/pdo_firebird/tests/fb4_datatypes_params.phpt @@ -0,0 +1,50 @@ +--TEST-- +PDO_Firebird: Supported Firebird 4.0 datatypes (parameters) +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--XLEAK-- +A bug in firebird causes a memory leak when calling `isc_attach_database()`. +See https://github.com/FirebirdSQL/firebird/issues/7849 +--FILE-- +prepare($sql); +$stmt->execute([12, 12.34, 12.34, '2024-05-04 12:59:34.239 Europe/Moscow', '12:59 Europe/Moscow', 12.34, 12.34]); +$data = $stmt->fetch(\PDO::FETCH_ASSOC); +$stmt->closeCursor(); +$str = json_encode($data, JSON_PRETTY_PRINT); +echo $str; +echo "\ndone\n"; +?> +--EXPECTF-- +{ + "I128": "12", + "N1": "12.34", + "N2": "12.34", + "TS_TZ": "%s 12:59:34.2390 Europe\/Moscow", + "T_TZ": "12:59:00.0000 Europe\/Moscow", + "DF16": "12.34", + "DF34": "12.34" +} +done