Skip to content

Commit 00e4588

Browse files
sim1984SakiTakamachi
authored andcommitted
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
1 parent d4ef8b9 commit 00e4588

File tree

5 files changed

+169
-0
lines changed

5 files changed

+169
-0
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ PHP NEWS
3535
. Added Pdo\Firebird::ATTR_API_VERSION. (SakiTakamachi)
3636
. Added getApiVersion() and removed from getAttribute().
3737
(SakiTakamachi)
38+
. Supported Firebird 4.0 datatypes. (sim1984)
3839

3940
- PGSQL:
4041
. pg_convert/pg_insert/pg_update/pg_delete ; regexes are now cached.

UPGRADING

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ PHP 8.4 UPGRADE NOTES
524524
. The content that is built changes depending on the value of FB_API_VER in
525525
ibase.h, so added static method Pdo\Firebird::getApiVersion() to obtain that
526526
value. This value can also be referenced from phpinfo.
527+
. Five new data types are now available: INT128, DEC16, DEC34, TIMESTAMP_TZ, TIME_TZ.
528+
These are available starting with Firebird 4.0.
527529

528530
- PDO_MYSQL:
529531
. getAttribute, enabled to get the value of ATTR_FETCH_TABLE_NAMES.

ext/pdo_firebird/firebird_driver.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,56 @@ static int php_firebird_preprocess(const zend_string* sql, char* sql_out, HashTa
460460
return 1;
461461
}
462462

463+
#if FB_API_VER >= 40
464+
/* set coercing a data type */
465+
static void set_coercing_data_type(XSQLDA* sqlda)
466+
{
467+
/* Data types introduced in Firebird 4.0 are difficult to process using the Firebird Legacy API. */
468+
/* These data types include DECFLOAT(16), DECFLOAT(34), INT128 (NUMERIC/DECIMAL(38, x)), */
469+
/* TIMESTAMP WITH TIME ZONE, and TIME WITH TIME ZONE. In any case, at least the first three data types */
470+
/* can only be mapped to strings. The last two too, but for them it is potentially possible to set */
471+
/* the display format, as is done for TIMESTAMP. This function allows you to ensure minimal performance */
472+
/* of queries if they contain columns and parameters of the above types. */
473+
unsigned int i;
474+
short dtype;
475+
short nullable;
476+
XSQLVAR* var;
477+
for (i=0, var = sqlda->sqlvar; i < sqlda->sqld; i++, var++) {
478+
dtype = (var->sqltype & ~1); /* drop flag bit */
479+
nullable = (var->sqltype & 1);
480+
switch(dtype) {
481+
case SQL_INT128:
482+
var->sqltype = SQL_VARYING + nullable;
483+
var->sqllen = 46;
484+
var->sqlscale = 0;
485+
break;
486+
487+
case SQL_DEC16:
488+
var->sqltype = SQL_VARYING + nullable;
489+
var->sqllen = 24;
490+
break;
491+
492+
case SQL_DEC34:
493+
var->sqltype = SQL_VARYING + nullable;
494+
var->sqllen = 43;
495+
break;
496+
497+
case SQL_TIMESTAMP_TZ:
498+
var->sqltype = SQL_VARYING + nullable;
499+
var->sqllen = 58;
500+
break;
501+
502+
case SQL_TIME_TZ:
503+
var->sqltype = SQL_VARYING + nullable;
504+
var->sqllen = 46;
505+
break;
506+
default:
507+
break;
508+
}
509+
}
510+
}
511+
#endif
512+
463513
/* map driver specific error message to PDO error */
464514
void php_firebird_set_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *state, const size_t state_len,
465515
const char *msg, const size_t msg_len) /* {{{ */
@@ -605,6 +655,11 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */
605655
break;
606656
}
607657

658+
#if FB_API_VER >= 40
659+
/* set coercing a data type */
660+
set_coercing_data_type(&S->out_sqlda);
661+
#endif
662+
608663
/* allocate the input descriptors */
609664
if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &num_sqlda)) {
610665
break;
@@ -618,6 +673,11 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */
618673
if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, S->in_sqlda)) {
619674
break;
620675
}
676+
677+
#if FB_API_VER >= 40
678+
/* set coercing a data type */
679+
set_coercing_data_type(S->in_sqlda);
680+
#endif
621681
}
622682

623683
stmt->driver_data = S;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
PDO_Firebird: Supported Firebird 4.0 datatypes
3+
--EXTENSIONS--
4+
pdo_firebird
5+
--SKIPIF--
6+
<?php require('skipif.inc');
7+
if (Pdo\Firebird::getApiVersion() < 40) {
8+
die('skip: Firebird API version must be greater than or equal to 40');
9+
}
10+
?>
11+
--XLEAK--
12+
A bug in firebird causes a memory leak when calling `isc_attach_database()`.
13+
See https://github.com/FirebirdSQL/firebird/issues/7849
14+
--FILE--
15+
<?php
16+
require 'testdb.inc';
17+
18+
$sql = <<<'SQL'
19+
SELECT
20+
CAST(15 AS BIGINT) AS i64,
21+
CAST(15 AS INT128) AS i128,
22+
123.97 AS N,
23+
CAST(123.97 AS NUMERIC(38,2)) AS N2,
24+
CAST('2024-05-04 12:59:34.239' AS TIMESTAMP) AS TS,
25+
CAST('2024-05-04 12:59:34.239 Europe/Moscow' AS TIMESTAMP WITH TIME ZONE) AS TS_TZ,
26+
CAST('12:59:34.239' AS TIME) AS T,
27+
CAST('12:59:34.239 Europe/Moscow' AS TIME WITH TIME ZONE) AS T_TZ,
28+
CAST(1.128 AS DECFLOAT(16)) AS df16,
29+
CAST(1.128 AS DECFLOAT(34)) AS df34
30+
FROM RDB$DATABASE
31+
SQL;
32+
33+
$dbh = getDbConnection();
34+
35+
$stmt = $dbh->prepare($sql);
36+
$stmt->execute();
37+
$data = $stmt->fetch(\PDO::FETCH_ASSOC);
38+
$stmt->closeCursor();
39+
$str = json_encode($data, JSON_PRETTY_PRINT);
40+
echo $str;
41+
echo "\ndone\n";
42+
?>
43+
--EXPECTF--
44+
{
45+
"I64": 15,
46+
"I128": "15",
47+
"N": "123.97",
48+
"N2": "123.97",
49+
"TS": "2024-05-04 12:59:34",
50+
"TS_TZ": "%s 12:59:34.2390 Europe\/Moscow",
51+
"T": "12:59:34",
52+
"T_TZ": "12:59:34.2390 Europe\/Moscow",
53+
"DF16": "1.128",
54+
"DF34": "1.128"
55+
}
56+
done
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
PDO_Firebird: Supported Firebird 4.0 datatypes (parameters)
3+
--EXTENSIONS--
4+
pdo_firebird
5+
--SKIPIF--
6+
<?php require('skipif.inc');
7+
if (Pdo\Firebird::getApiVersion() < 40) {
8+
die('skip: Firebird API version must be greater than or equal to 40');
9+
}
10+
?>
11+
--XLEAK--
12+
A bug in firebird causes a memory leak when calling `isc_attach_database()`.
13+
See https://github.com/FirebirdSQL/firebird/issues/7849
14+
--FILE--
15+
<?php
16+
require 'testdb.inc';
17+
18+
$sql = <<<'SQL'
19+
SELECT
20+
CAST(? AS INT128) AS i128,
21+
CAST(? AS NUMERIC(18,2)) AS N1,
22+
CAST(? AS NUMERIC(38,2)) AS N2,
23+
CAST(? AS TIMESTAMP WITH TIME ZONE) AS TS_TZ,
24+
CAST(? AS TIME WITH TIME ZONE) AS T_TZ,
25+
CAST(? AS DECFLOAT(16)) AS df16,
26+
CAST(? AS DECFLOAT(34)) AS df34
27+
FROM RDB$DATABASE
28+
SQL;
29+
30+
$dbh = getDbConnection();
31+
32+
$stmt = $dbh->prepare($sql);
33+
$stmt->execute([12, 12.34, 12.34, '2024-05-04 12:59:34.239 Europe/Moscow', '12:59 Europe/Moscow', 12.34, 12.34]);
34+
$data = $stmt->fetch(\PDO::FETCH_ASSOC);
35+
$stmt->closeCursor();
36+
$str = json_encode($data, JSON_PRETTY_PRINT);
37+
echo $str;
38+
echo "\ndone\n";
39+
?>
40+
--EXPECTF--
41+
{
42+
"I128": "12",
43+
"N1": "12.34",
44+
"N2": "12.34",
45+
"TS_TZ": "%s 12:59:34.2390 Europe\/Moscow",
46+
"T_TZ": "12:59:00.0000 Europe\/Moscow",
47+
"DF16": "12.34",
48+
"DF34": "12.34"
49+
}
50+
done

0 commit comments

Comments
 (0)