Skip to content

Commit e10257b

Browse files
jbylundweltling
authored andcommitted
Don't roundtrip to the database to get the column type if you already know it
add_assoc_string now takes just three args nikic's fix to move pqclear outside the if, would be a possible memory leak inside the if (joe) check behavior of getColumnMeta
1 parent ea05989 commit e10257b

File tree

2 files changed

+159
-25
lines changed

2 files changed

+159
-25
lines changed

ext/pdo_pgsql/pgsql_statement.c

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,27 @@
3636
#endif
3737

3838
/* from postgresql/src/include/catalog/pg_type.h */
39+
#define BOOLLABEL "bool"
3940
#define BOOLOID 16
41+
#define BYTEALABEL "bytea"
4042
#define BYTEAOID 17
41-
#define INT8OID 20
43+
#define DATELABEL "date"
44+
#define DATEOID 1082
45+
#define INT2LABEL "int2"
4246
#define INT2OID 21
47+
#define INT4LABEL "int4"
4348
#define INT4OID 23
44-
#define TEXTOID 25
49+
#define INT8LABEL "int8"
50+
#define INT8OID 20
4551
#define OIDOID 26
52+
#define TEXTLABEL "text"
53+
#define TEXTOID 25
54+
#define TIMESTAMPLABEL "timestamp"
55+
#define TIMESTAMPOID 1114
56+
#define VARCHARLABEL "varchar"
57+
#define VARCHAROID 1043
58+
59+
4660

4761
static int pgsql_stmt_dtor(pdo_stmt_t *stmt)
4862
{
@@ -591,29 +605,46 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *r
591605
array_init(return_value);
592606
add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type);
593607

594-
/* Fetch metadata from Postgres system catalogue */
595-
spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type);
596-
res = PQexec(S->H->server, q);
597-
efree(q);
598-
599-
status = PQresultStatus(res);
600-
601-
if (status != PGRES_TUPLES_OK) {
602-
/* Failed to get system catalogue, but return success
603-
* with the data we have collected so far
604-
*/
605-
goto done;
606-
}
607-
608-
/* We want exactly one row returned */
609-
if (1 != PQntuples(res)) {
610-
goto done;
611-
}
612-
613-
add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0));
614-
done:
615-
PQclear(res);
616-
return 1;
608+
switch (S->cols[colno].pgsql_type) {
609+
case BOOLOID:
610+
add_assoc_string(return_value, "native_type", BOOLLABEL);
611+
break;
612+
case BYTEAOID:
613+
add_assoc_string(return_value, "native_type", BYTEALABEL);
614+
break;
615+
case INT8OID:
616+
add_assoc_string(return_value, "native_type", INT8LABEL);
617+
break;
618+
case INT2OID:
619+
add_assoc_string(return_value, "native_type", INT2LABEL);
620+
break;
621+
case INT4OID:
622+
add_assoc_string(return_value, "native_type", INT4LABEL);
623+
break;
624+
case TEXTOID:
625+
add_assoc_string(return_value, "native_type", TEXTLABEL);
626+
break;
627+
case VARCHAROID:
628+
add_assoc_string(return_value, "native_type", VARCHARLABEL);
629+
break;
630+
case DATEOID:
631+
add_assoc_string(return_value, "native_type", DATELABEL);
632+
break;
633+
case TIMESTAMPOID:
634+
add_assoc_string(return_value, "native_type", TIMESTAMPLABEL);
635+
break;
636+
default:
637+
/* Fetch metadata from Postgres system catalogue */
638+
spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type);
639+
res = PQexec(S->H->server, q);
640+
efree(q);
641+
status = PQresultStatus(res);
642+
if (status == PGRES_TUPLES_OK && 1 == PQntuples(res)) {
643+
add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0));
644+
}
645+
PQclear(res);
646+
}
647+
return 1;
617648
}
618649

619650
static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt)

ext/pdo_pgsql/tests/bug62498.phpt

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
--TEST--
2+
PDO PgSQL Bug #62498 (pdo_pgsql inefficient when getColumnMeta() is used)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
6+
require dirname(__FILE__) . '/config.inc';
7+
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
8+
PDOTest::skip();
9+
?>
10+
--FILE--
11+
<?php
12+
echo "Begin test...\n";
13+
14+
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
15+
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
16+
$db->setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
17+
18+
// create the table
19+
$db->exec("CREATE TEMPORARY TABLE bugtest_62498 (intcol INTEGER, stringcol VARCHAR(255), boolcol BOOLEAN, datecol DATE)");
20+
21+
// insert some data
22+
$statement = $db->prepare("INSERT INTO bugtest_62498 (intcol, stringcol, boolcol, datecol) VALUES (:intval, :stringval, :boolval, :dateval)");
23+
$statement->execute(array(
24+
"intval" => "42",
25+
"stringval" => "The Answer",
26+
"boolval" => true,
27+
"dateval" => '2015-12-14',
28+
));
29+
30+
$select = $db->query('SELECT intcol, stringcol, boolcol, datecol FROM bugtest_62498');
31+
$meta = [];
32+
for ($i=0; $i < 4; $i++) {
33+
$meta[] = $select->getColumnMeta(0);
34+
}
35+
var_dump($meta);
36+
37+
?>
38+
Done
39+
--EXPECT--
40+
Begin test...
41+
array(4) {
42+
[0]=>
43+
array(6) {
44+
["pgsql:oid"]=>
45+
int(23)
46+
["native_type"]=>
47+
string(4) "int4"
48+
["name"]=>
49+
string(6) "intcol"
50+
["len"]=>
51+
int(4)
52+
["precision"]=>
53+
int(-1)
54+
["pdo_type"]=>
55+
int(1)
56+
}
57+
[1]=>
58+
array(6) {
59+
["pgsql:oid"]=>
60+
int(23)
61+
["native_type"]=>
62+
string(4) "int4"
63+
["name"]=>
64+
string(6) "intcol"
65+
["len"]=>
66+
int(4)
67+
["precision"]=>
68+
int(-1)
69+
["pdo_type"]=>
70+
int(1)
71+
}
72+
[2]=>
73+
array(6) {
74+
["pgsql:oid"]=>
75+
int(23)
76+
["native_type"]=>
77+
string(4) "int4"
78+
["name"]=>
79+
string(6) "intcol"
80+
["len"]=>
81+
int(4)
82+
["precision"]=>
83+
int(-1)
84+
["pdo_type"]=>
85+
int(1)
86+
}
87+
[3]=>
88+
array(6) {
89+
["pgsql:oid"]=>
90+
int(23)
91+
["native_type"]=>
92+
string(4) "int4"
93+
["name"]=>
94+
string(6) "intcol"
95+
["len"]=>
96+
int(4)
97+
["precision"]=>
98+
int(-1)
99+
["pdo_type"]=>
100+
int(1)
101+
}
102+
}
103+
Done

0 commit comments

Comments
 (0)