Skip to content

Commit 5eec4d8

Browse files
committed
pgsql: Avoid duplicating strings and factor out parameter building code
1 parent da96382 commit 5eec4d8

File tree

1 file changed

+53
-91
lines changed

1 file changed

+53
-91
lines changed

ext/pgsql/pgsql.c

Lines changed: 53 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,26 +1223,55 @@ PHP_FUNCTION(pg_query)
12231223
}
12241224
}
12251225

1226-
static void _php_pgsql_free_params(char **params, int num_params)
1226+
/* The char pointer MUST refer to the char* of a zend_string struct */
1227+
static void php_pgsql_zend_string_release_from_char_pointer(char *ptr) {
1228+
zend_string_release((zend_string*) (ptr - XtOffsetOf(zend_string, val)));
1229+
}
1230+
1231+
static void _php_pgsql_free_params(char **params, uint32_t num_params)
12271232
{
1228-
int i;
1229-
for (i = 0; i < num_params; i++) {
1233+
for (uint32_t i = 0; i < num_params; i++) {
12301234
if (params[i]) {
1231-
efree(params[i]);
1235+
php_pgsql_zend_string_release_from_char_pointer(params[i]);
12321236
}
12331237
}
12341238
efree(params);
12351239
}
12361240

1241+
static char **php_pgsql_make_arguments(const HashTable *param_arr, int *num_params)
1242+
{
1243+
/* This conversion is safe because of the limit of number of elements in a table. */
1244+
*num_params = (int) zend_hash_num_elements(param_arr);
1245+
char **params = safe_emalloc(sizeof(char *), *num_params, 0);
1246+
uint32_t i = 0;
1247+
1248+
ZEND_HASH_FOREACH_VAL(param_arr, zval *tmp) {
1249+
ZVAL_DEREF(tmp);
1250+
if (Z_TYPE_P(tmp) == IS_NULL) {
1251+
params[i] = NULL;
1252+
} else {
1253+
zend_string *param_str = zval_try_get_string(tmp);
1254+
if (!param_str) {
1255+
_php_pgsql_free_params(params, i);
1256+
return NULL;
1257+
}
1258+
params[i] = ZSTR_VAL(param_str);
1259+
}
1260+
i++;
1261+
} ZEND_HASH_FOREACH_END();
1262+
1263+
return params;
1264+
}
1265+
12371266
/* Execute a query */
12381267
PHP_FUNCTION(pg_query_params)
12391268
{
12401269
zval *pgsql_link = NULL;
1241-
zval *pv_param_arr, *tmp;
1270+
zval *pv_param_arr;
12421271
char *query;
12431272
size_t query_len;
12441273
bool leftover = false;
1245-
int num_params = 0;
1274+
int num_params;
12461275
char **params = NULL;
12471276
pgsql_link_handle *link;
12481277
PGconn *pgsql;
@@ -1286,26 +1315,9 @@ PHP_FUNCTION(pg_query_params)
12861315
php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
12871316
}
12881317

1289-
num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
1290-
if (num_params > 0) {
1291-
int i = 0;
1292-
params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
1293-
1294-
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
1295-
ZVAL_DEREF(tmp);
1296-
if (Z_TYPE_P(tmp) == IS_NULL) {
1297-
params[i] = NULL;
1298-
} else {
1299-
zend_string *param_str = zval_try_get_string(tmp);
1300-
if (!param_str) {
1301-
_php_pgsql_free_params(params, i);
1302-
RETURN_THROWS();
1303-
}
1304-
params[i] = estrndup(ZSTR_VAL(param_str), ZSTR_LEN(param_str));
1305-
zend_string_release(param_str);
1306-
}
1307-
i++;
1308-
} ZEND_HASH_FOREACH_END();
1318+
params = php_pgsql_make_arguments(Z_ARRVAL_P(pv_param_arr), &num_params);
1319+
if (UNEXPECTED(!params)) {
1320+
RETURN_THROWS();
13091321
}
13101322

13111323
pgsql_result = PQexecParams(pgsql, query, num_params,
@@ -1440,11 +1452,11 @@ PHP_FUNCTION(pg_prepare)
14401452
PHP_FUNCTION(pg_execute)
14411453
{
14421454
zval *pgsql_link = NULL;
1443-
zval *pv_param_arr, *tmp;
1455+
zval *pv_param_arr;
14441456
char *stmtname;
14451457
size_t stmtname_len;
14461458
bool leftover = false;
1447-
int num_params = 0;
1459+
int num_params;
14481460
char **params = NULL;
14491461
PGconn *pgsql;
14501462
pgsql_link_handle *link;
@@ -1488,25 +1500,9 @@ PHP_FUNCTION(pg_execute)
14881500
php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
14891501
}
14901502

1491-
num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
1492-
if (num_params > 0) {
1493-
int i = 0;
1494-
params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
1495-
1496-
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
1497-
ZVAL_DEREF(tmp);
1498-
if (Z_TYPE_P(tmp) == IS_NULL) {
1499-
params[i] = NULL;
1500-
} else {
1501-
zend_string *tmp_str;
1502-
zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
1503-
1504-
params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
1505-
zend_tmp_string_release(tmp_str);
1506-
}
1507-
1508-
i++;
1509-
} ZEND_HASH_FOREACH_END();
1503+
params = php_pgsql_make_arguments(Z_ARRVAL_P(pv_param_arr), &num_params);
1504+
if (UNEXPECTED(!params)) {
1505+
RETURN_THROWS();
15101506
}
15111507

15121508
pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
@@ -4034,9 +4030,9 @@ PHP_FUNCTION(pg_send_query)
40344030
/* {{{ Send asynchronous parameterized query */
40354031
PHP_FUNCTION(pg_send_query_params)
40364032
{
4037-
zval *pgsql_link, *pv_param_arr, *tmp;
4033+
zval *pgsql_link, *pv_param_arr;
40384034
pgsql_link_handle *link;
4039-
int num_params = 0;
4035+
int num_params;
40404036
char **params = NULL;
40414037
char *query;
40424038
size_t query_len;
@@ -4066,25 +4062,9 @@ PHP_FUNCTION(pg_send_query_params)
40664062
"There are results on this connection. Call pg_get_result() until it returns FALSE");
40674063
}
40684064

4069-
num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
4070-
if (num_params > 0) {
4071-
int i = 0;
4072-
params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4073-
4074-
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
4075-
ZVAL_DEREF(tmp);
4076-
if (Z_TYPE_P(tmp) == IS_NULL) {
4077-
params[i] = NULL;
4078-
} else {
4079-
zend_string *tmp_str;
4080-
zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
4081-
4082-
params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
4083-
zend_tmp_string_release(tmp_str);
4084-
}
4085-
4086-
i++;
4087-
} ZEND_HASH_FOREACH_END();
4065+
params = php_pgsql_make_arguments(Z_ARRVAL_P(pv_param_arr), &num_params);
4066+
if (UNEXPECTED(!params)) {
4067+
RETURN_THROWS();
40884068
}
40894069

40904070
if (PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
@@ -4206,8 +4186,8 @@ PHP_FUNCTION(pg_send_execute)
42064186
{
42074187
zval *pgsql_link;
42084188
pgsql_link_handle *link;
4209-
zval *pv_param_arr, *tmp;
4210-
int num_params = 0;
4189+
zval *pv_param_arr;
4190+
int num_params;
42114191
char **params = NULL;
42124192
char *stmtname;
42134193
size_t stmtname_len;
@@ -4237,27 +4217,9 @@ PHP_FUNCTION(pg_send_execute)
42374217
"There are results on this connection. Call pg_get_result() until it returns FALSE");
42384218
}
42394219

4240-
num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
4241-
if (num_params > 0) {
4242-
int i = 0;
4243-
params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4244-
4245-
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
4246-
ZVAL_DEREF(tmp);
4247-
if (Z_TYPE_P(tmp) == IS_NULL) {
4248-
params[i] = NULL;
4249-
} else {
4250-
zend_string *tmp_str = zval_try_get_string(tmp);
4251-
if (UNEXPECTED(!tmp_str)) {
4252-
_php_pgsql_free_params(params, i);
4253-
return;
4254-
}
4255-
params[i] = estrndup(ZSTR_VAL(tmp_str), ZSTR_LEN(tmp_str));
4256-
zend_string_release(tmp_str);
4257-
}
4258-
4259-
i++;
4260-
} ZEND_HASH_FOREACH_END();
4220+
params = php_pgsql_make_arguments(Z_ARRVAL_P(pv_param_arr), &num_params);
4221+
if (UNEXPECTED(!params)) {
4222+
RETURN_THROWS();
42614223
}
42624224

42634225
if (PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {

0 commit comments

Comments
 (0)