Skip to content

Commit 4200b32

Browse files
committed
Optimized the behavior of PDO::PARAM_XXX
Modify test DB attributes
1 parent 1b846f8 commit 4200b32

File tree

2 files changed

+220
-49
lines changed

2 files changed

+220
-49
lines changed

ext/pdo_pgsql/pgsql_statement.c

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -348,67 +348,112 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *
348348
parameter = &param->parameter;
349349
}
350350

351-
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB &&
352-
Z_TYPE_P(parameter) == IS_RESOURCE) {
353-
php_stream *stm;
354-
php_stream_from_zval_no_verify(stm, parameter);
355-
if (stm) {
356-
if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) {
357-
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract;
358-
pdo_pgsql_bound_param *P = param->driver_data;
359-
360-
if (P == NULL) {
361-
P = ecalloc(1, sizeof(*P));
362-
param->driver_data = P;
351+
exec_pre_retry:
352+
switch (PDO_PARAM_TYPE(param->param_type)) {
353+
case PDO_PARAM_NULL:
354+
S->param_values[param->paramno] = NULL;
355+
S->param_lengths[param->paramno] = 0;
356+
break;
357+
358+
case PDO_PARAM_STMT:
359+
return 0;
360+
361+
case PDO_PARAM_INT:
362+
if (Z_TYPE_P(parameter) == IS_NULL) {
363+
param->param_type = PDO_PARAM_NULL;
364+
goto exec_pre_retry;
365+
}
366+
convert_to_long(parameter);
367+
convert_to_string(parameter);
368+
S->param_values[param->paramno] = Z_STRVAL_P(parameter);
369+
S->param_lengths[param->paramno] = Z_STRLEN_P(parameter);
370+
S->param_formats[param->paramno] = 0;
371+
#if SIZEOF_ZEND_LONG >= 8
372+
S->param_types[param->paramno] = INT8OID;
373+
#else
374+
S->param_types[param->paramno] = INT4OID;
375+
#endif
376+
break;
377+
378+
case PDO_PARAM_BOOL:
379+
if (Z_TYPE_P(parameter) == IS_NULL) {
380+
param->param_type = PDO_PARAM_NULL;
381+
goto exec_pre_retry;
382+
}
383+
convert_to_boolean(parameter);
384+
S->param_values[param->paramno] = Z_TYPE_P(parameter) == IS_TRUE ? "t" : "f";
385+
S->param_lengths[param->paramno] = 1;
386+
S->param_formats[param->paramno] = 0;
387+
break;
388+
389+
case PDO_PARAM_LOB:
390+
if (Z_TYPE_P(parameter) == IS_RESOURCE) {
391+
php_stream *stm;
392+
php_stream_from_zval_no_verify(stm, parameter);
393+
if (stm) {
394+
if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) {
395+
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract;
396+
pdo_pgsql_bound_param *P = param->driver_data;
397+
398+
if (P == NULL) {
399+
P = ecalloc(1, sizeof(*P));
400+
param->driver_data = P;
401+
}
402+
P->oid = htonl(self->oid);
403+
S->param_values[param->paramno] = (char*)&P->oid;
404+
S->param_lengths[param->paramno] = sizeof(P->oid);
405+
S->param_formats[param->paramno] = 1;
406+
S->param_types[param->paramno] = OIDOID;
407+
return 1;
408+
} else {
409+
zend_string *str = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
410+
if (str != NULL) {
411+
ZVAL_STR(parameter, str);
412+
} else {
413+
ZVAL_EMPTY_STRING(parameter);
414+
}
415+
}
416+
} else {
417+
/* expected a stream resource */
418+
pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
419+
return 0;
363420
}
364-
P->oid = htonl(self->oid);
365-
S->param_values[param->paramno] = (char*)&P->oid;
366-
S->param_lengths[param->paramno] = sizeof(P->oid);
367-
S->param_formats[param->paramno] = 1;
368-
S->param_types[param->paramno] = OIDOID;
369-
return 1;
421+
} else if (Z_TYPE_P(parameter) == IS_NULL) {
422+
param->param_type = PDO_PARAM_NULL;
423+
goto exec_pre_retry;
370424
} else {
371-
zend_string *str = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
372-
if (str != NULL) {
373-
ZVAL_STR(parameter, str);
374-
} else {
375-
ZVAL_EMPTY_STRING(parameter);
425+
// fallback
426+
if (!try_convert_to_string(parameter)) {
427+
return 0;
376428
}
429+
S->param_values[param->paramno] = Z_STRVAL_P(parameter);
430+
S->param_lengths[param->paramno] = Z_STRLEN_P(parameter);
431+
S->param_types[param->paramno] = 0;
432+
S->param_formats[param->paramno] = 1;
377433
}
378-
} else {
379-
/* expected a stream resource */
380-
pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
381-
return 0;
382-
}
383-
}
384-
385-
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
386-
Z_TYPE_P(parameter) == IS_NULL) {
387-
S->param_values[param->paramno] = NULL;
388-
S->param_lengths[param->paramno] = 0;
389-
} else if (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE) {
390-
S->param_values[param->paramno] = Z_TYPE_P(parameter) == IS_TRUE ? "t" : "f";
391-
S->param_lengths[param->paramno] = 1;
392-
S->param_formats[param->paramno] = 0;
393-
} else {
394-
convert_to_string(parameter);
395-
S->param_values[param->paramno] = Z_STRVAL_P(parameter);
396-
S->param_lengths[param->paramno] = Z_STRLEN_P(parameter);
397-
S->param_formats[param->paramno] = 0;
398-
}
434+
break;
399435

400-
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
401-
S->param_types[param->paramno] = 0;
402-
S->param_formats[param->paramno] = 1;
403-
} else {
404-
S->param_types[param->paramno] = 0;
436+
case PDO_PARAM_STR:
437+
default:
438+
if (Z_TYPE_P(parameter) == IS_NULL) {
439+
param->param_type = PDO_PARAM_NULL;
440+
goto exec_pre_retry;
441+
}
442+
if (!try_convert_to_string(parameter)) {
443+
return 0;
444+
}
445+
S->param_values[param->paramno] = Z_STRVAL_P(parameter);
446+
S->param_lengths[param->paramno] = Z_STRLEN_P(parameter);
447+
S->param_formats[param->paramno] = 0;
448+
break;
405449
}
406450
}
407451
break;
408452
}
409453
} else if (param->is_param && event_type == PDO_PARAM_EVT_NORMALIZE) {
410454
/* We need to manually convert to a pg native boolean value */
411455
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL &&
456+
Z_TYPE_P(&param->parameter) != IS_NULL &&
412457
((param->param_type & PDO_PARAM_INPUT_OUTPUT) != PDO_PARAM_INPUT_OUTPUT)) {
413458
const char *s = zend_is_true(&param->parameter) ? "t" : "f";
414459
param->param_type = PDO_PARAM_STR;

ext/pdo_pgsql/tests/pdo_param.phpt

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
--TEST--
2+
PDO PgSQL PDOStatement PDO::PARAM_XXX
3+
--EXTENSIONS--
4+
pdo
5+
pdo_pgsql
6+
--SKIPIF--
7+
<?php
8+
require __DIR__ . '/config.inc';
9+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
10+
PDOTest::skip();
11+
?>
12+
--FILE--
13+
<?php
14+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
15+
$db = PDOTest::test_factory(__DIR__ . '/common.phpt');
16+
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
17+
18+
// The LOB test is omitted because it exists separately.
19+
foreach ([
20+
'PDO::PARAM_STR',
21+
'PDO::PARAM_INT',
22+
'PDO::PARAM_BOOL',
23+
'PDO::PARAM_NULL',
24+
] as $param_type_const) {
25+
foreach ([
26+
null,
27+
0,
28+
8,
29+
'',
30+
'0',
31+
'10',
32+
'str',
33+
true,
34+
false,
35+
] as $val) {
36+
foreach ([1, 0] as $emulate) {
37+
printf('%s, var = %s, PDO::ATTR_EMULATE_PREPARES = %d: ', $param_type_const, var_export($val, true), $emulate);
38+
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate);
39+
$stmt = $db->prepare('SELECT :val as val');
40+
$stmt->bindValue(':val', $val, constant($param_type_const));
41+
$stmt->execute();
42+
$row = $stmt->fetch(PDO::FETCH_ASSOC);
43+
var_dump($row['val']);
44+
}
45+
}
46+
if ($param_type_const !== 'PDO::PARAM_NULL') {
47+
echo PHP_EOL;
48+
}
49+
}
50+
?>
51+
--EXPECT--
52+
PDO::PARAM_STR, var = NULL, PDO::ATTR_EMULATE_PREPARES = 1: NULL
53+
PDO::PARAM_STR, var = NULL, PDO::ATTR_EMULATE_PREPARES = 0: NULL
54+
PDO::PARAM_STR, var = 0, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "0"
55+
PDO::PARAM_STR, var = 0, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "0"
56+
PDO::PARAM_STR, var = 8, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "8"
57+
PDO::PARAM_STR, var = 8, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "8"
58+
PDO::PARAM_STR, var = '', PDO::ATTR_EMULATE_PREPARES = 1: string(0) ""
59+
PDO::PARAM_STR, var = '', PDO::ATTR_EMULATE_PREPARES = 0: string(0) ""
60+
PDO::PARAM_STR, var = '0', PDO::ATTR_EMULATE_PREPARES = 1: string(1) "0"
61+
PDO::PARAM_STR, var = '0', PDO::ATTR_EMULATE_PREPARES = 0: string(1) "0"
62+
PDO::PARAM_STR, var = '10', PDO::ATTR_EMULATE_PREPARES = 1: string(2) "10"
63+
PDO::PARAM_STR, var = '10', PDO::ATTR_EMULATE_PREPARES = 0: string(2) "10"
64+
PDO::PARAM_STR, var = 'str', PDO::ATTR_EMULATE_PREPARES = 1: string(3) "str"
65+
PDO::PARAM_STR, var = 'str', PDO::ATTR_EMULATE_PREPARES = 0: string(3) "str"
66+
PDO::PARAM_STR, var = true, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "1"
67+
PDO::PARAM_STR, var = true, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "1"
68+
PDO::PARAM_STR, var = false, PDO::ATTR_EMULATE_PREPARES = 1: string(0) ""
69+
PDO::PARAM_STR, var = false, PDO::ATTR_EMULATE_PREPARES = 0: string(0) ""
70+
71+
PDO::PARAM_INT, var = NULL, PDO::ATTR_EMULATE_PREPARES = 1: NULL
72+
PDO::PARAM_INT, var = NULL, PDO::ATTR_EMULATE_PREPARES = 0: NULL
73+
PDO::PARAM_INT, var = 0, PDO::ATTR_EMULATE_PREPARES = 1: int(0)
74+
PDO::PARAM_INT, var = 0, PDO::ATTR_EMULATE_PREPARES = 0: int(0)
75+
PDO::PARAM_INT, var = 8, PDO::ATTR_EMULATE_PREPARES = 1: int(8)
76+
PDO::PARAM_INT, var = 8, PDO::ATTR_EMULATE_PREPARES = 0: int(8)
77+
PDO::PARAM_INT, var = '', PDO::ATTR_EMULATE_PREPARES = 1: int(0)
78+
PDO::PARAM_INT, var = '', PDO::ATTR_EMULATE_PREPARES = 0: int(0)
79+
PDO::PARAM_INT, var = '0', PDO::ATTR_EMULATE_PREPARES = 1: int(0)
80+
PDO::PARAM_INT, var = '0', PDO::ATTR_EMULATE_PREPARES = 0: int(0)
81+
PDO::PARAM_INT, var = '10', PDO::ATTR_EMULATE_PREPARES = 1: int(10)
82+
PDO::PARAM_INT, var = '10', PDO::ATTR_EMULATE_PREPARES = 0: int(10)
83+
PDO::PARAM_INT, var = 'str', PDO::ATTR_EMULATE_PREPARES = 1: int(0)
84+
PDO::PARAM_INT, var = 'str', PDO::ATTR_EMULATE_PREPARES = 0: int(0)
85+
PDO::PARAM_INT, var = true, PDO::ATTR_EMULATE_PREPARES = 1: int(1)
86+
PDO::PARAM_INT, var = true, PDO::ATTR_EMULATE_PREPARES = 0: int(1)
87+
PDO::PARAM_INT, var = false, PDO::ATTR_EMULATE_PREPARES = 1: int(0)
88+
PDO::PARAM_INT, var = false, PDO::ATTR_EMULATE_PREPARES = 0: int(0)
89+
90+
PDO::PARAM_BOOL, var = NULL, PDO::ATTR_EMULATE_PREPARES = 1: NULL
91+
PDO::PARAM_BOOL, var = NULL, PDO::ATTR_EMULATE_PREPARES = 0: NULL
92+
PDO::PARAM_BOOL, var = 0, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "f"
93+
PDO::PARAM_BOOL, var = 0, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "f"
94+
PDO::PARAM_BOOL, var = 8, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "t"
95+
PDO::PARAM_BOOL, var = 8, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "t"
96+
PDO::PARAM_BOOL, var = '', PDO::ATTR_EMULATE_PREPARES = 1: string(1) "f"
97+
PDO::PARAM_BOOL, var = '', PDO::ATTR_EMULATE_PREPARES = 0: string(1) "f"
98+
PDO::PARAM_BOOL, var = '0', PDO::ATTR_EMULATE_PREPARES = 1: string(1) "f"
99+
PDO::PARAM_BOOL, var = '0', PDO::ATTR_EMULATE_PREPARES = 0: string(1) "f"
100+
PDO::PARAM_BOOL, var = '10', PDO::ATTR_EMULATE_PREPARES = 1: string(1) "t"
101+
PDO::PARAM_BOOL, var = '10', PDO::ATTR_EMULATE_PREPARES = 0: string(1) "t"
102+
PDO::PARAM_BOOL, var = 'str', PDO::ATTR_EMULATE_PREPARES = 1: string(1) "t"
103+
PDO::PARAM_BOOL, var = 'str', PDO::ATTR_EMULATE_PREPARES = 0: string(1) "t"
104+
PDO::PARAM_BOOL, var = true, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "t"
105+
PDO::PARAM_BOOL, var = true, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "t"
106+
PDO::PARAM_BOOL, var = false, PDO::ATTR_EMULATE_PREPARES = 1: string(1) "f"
107+
PDO::PARAM_BOOL, var = false, PDO::ATTR_EMULATE_PREPARES = 0: string(1) "f"
108+
109+
PDO::PARAM_NULL, var = NULL, PDO::ATTR_EMULATE_PREPARES = 1: NULL
110+
PDO::PARAM_NULL, var = NULL, PDO::ATTR_EMULATE_PREPARES = 0: NULL
111+
PDO::PARAM_NULL, var = 0, PDO::ATTR_EMULATE_PREPARES = 1: NULL
112+
PDO::PARAM_NULL, var = 0, PDO::ATTR_EMULATE_PREPARES = 0: NULL
113+
PDO::PARAM_NULL, var = 8, PDO::ATTR_EMULATE_PREPARES = 1: NULL
114+
PDO::PARAM_NULL, var = 8, PDO::ATTR_EMULATE_PREPARES = 0: NULL
115+
PDO::PARAM_NULL, var = '', PDO::ATTR_EMULATE_PREPARES = 1: NULL
116+
PDO::PARAM_NULL, var = '', PDO::ATTR_EMULATE_PREPARES = 0: NULL
117+
PDO::PARAM_NULL, var = '0', PDO::ATTR_EMULATE_PREPARES = 1: NULL
118+
PDO::PARAM_NULL, var = '0', PDO::ATTR_EMULATE_PREPARES = 0: NULL
119+
PDO::PARAM_NULL, var = '10', PDO::ATTR_EMULATE_PREPARES = 1: NULL
120+
PDO::PARAM_NULL, var = '10', PDO::ATTR_EMULATE_PREPARES = 0: NULL
121+
PDO::PARAM_NULL, var = 'str', PDO::ATTR_EMULATE_PREPARES = 1: NULL
122+
PDO::PARAM_NULL, var = 'str', PDO::ATTR_EMULATE_PREPARES = 0: NULL
123+
PDO::PARAM_NULL, var = true, PDO::ATTR_EMULATE_PREPARES = 1: NULL
124+
PDO::PARAM_NULL, var = true, PDO::ATTR_EMULATE_PREPARES = 0: NULL
125+
PDO::PARAM_NULL, var = false, PDO::ATTR_EMULATE_PREPARES = 1: NULL
126+
PDO::PARAM_NULL, var = false, PDO::ATTR_EMULATE_PREPARES = 0: NULL

0 commit comments

Comments
 (0)