PDO_Firebird: Supported Firebird 4.0 datatypes (#14897)

Five new data types are now available: INT128, DEC16, DEC34, TIMESTAMP_TZ, TIME_TZ.
These are available starting with Firebird 4.0.

closes #14897
This commit is contained in:
Simonov Denis 2024-07-09 16:58:02 +03:00 committed by Saki Takamachi
parent d4ef8b97f5
commit 00e45887fa
No known key found for this signature in database
GPG Key ID: 770426E17EBBB3DD
5 changed files with 169 additions and 0 deletions

1
NEWS
View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -0,0 +1,56 @@
--TEST--
PDO_Firebird: Supported Firebird 4.0 datatypes
--EXTENSIONS--
pdo_firebird
--SKIPIF--
<?php require('skipif.inc');
if (Pdo\Firebird::getApiVersion() < 40) {
die('skip: Firebird API version must be greater than or equal to 40');
}
?>
--XLEAK--
A bug in firebird causes a memory leak when calling `isc_attach_database()`.
See https://github.com/FirebirdSQL/firebird/issues/7849
--FILE--
<?php
require 'testdb.inc';
$sql = <<<'SQL'
SELECT
CAST(15 AS BIGINT) AS i64,
CAST(15 AS INT128) AS i128,
123.97 AS N,
CAST(123.97 AS NUMERIC(38,2)) AS N2,
CAST('2024-05-04 12:59:34.239' AS TIMESTAMP) AS TS,
CAST('2024-05-04 12:59:34.239 Europe/Moscow' AS TIMESTAMP WITH TIME ZONE) AS TS_TZ,
CAST('12:59:34.239' AS TIME) AS T,
CAST('12:59:34.239 Europe/Moscow' AS TIME WITH TIME ZONE) AS T_TZ,
CAST(1.128 AS DECFLOAT(16)) AS df16,
CAST(1.128 AS DECFLOAT(34)) AS df34
FROM RDB$DATABASE
SQL;
$dbh = getDbConnection();
$stmt = $dbh->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

View File

@ -0,0 +1,50 @@
--TEST--
PDO_Firebird: Supported Firebird 4.0 datatypes (parameters)
--EXTENSIONS--
pdo_firebird
--SKIPIF--
<?php require('skipif.inc');
if (Pdo\Firebird::getApiVersion() < 40) {
die('skip: Firebird API version must be greater than or equal to 40');
}
?>
--XLEAK--
A bug in firebird causes a memory leak when calling `isc_attach_database()`.
See https://github.com/FirebirdSQL/firebird/issues/7849
--FILE--
<?php
require 'testdb.inc';
$sql = <<<'SQL'
SELECT
CAST(? AS INT128) AS i128,
CAST(? AS NUMERIC(18,2)) AS N1,
CAST(? AS NUMERIC(38,2)) AS N2,
CAST(? AS TIMESTAMP WITH TIME ZONE) AS TS_TZ,
CAST(? AS TIME WITH TIME ZONE) AS T_TZ,
CAST(? AS DECFLOAT(16)) AS df16,
CAST(? AS DECFLOAT(34)) AS df34
FROM RDB$DATABASE
SQL;
$dbh = getDbConnection();
$stmt = $dbh->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