Skip to content

Commit 91c72df

Browse files
committed
Refactor _php_ibase_fetch_hash()
1 parent f24057e commit 91c72df

File tree

2 files changed

+132
-58
lines changed

2 files changed

+132
-58
lines changed

ibase_query.c

Lines changed: 129 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,69 +1527,71 @@ static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type)
15271527
zval *result_arg;
15281528
zend_long flag = 0;
15291529
zend_long i, array_cnt = 0;
1530-
ibase_result *ib_result;
1530+
ibase_query *ib_query;
15311531

15321532
RESET_ERRMSG;
15331533

15341534
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result_arg, &flag)) {
1535-
return;
1535+
RETURN_FALSE;
15361536
}
15371537

1538-
ib_result = (ibase_result *)zend_fetch_resource_ex(result_arg, LE_RESULT, le_result);
1538+
if(_php_ibase_fetch_query_res(result_arg, &ib_query)) {
1539+
RETURN_FALSE;
1540+
}
1541+
1542+
assert(ib_query->out_fields_count > 0);
15391543

1540-
if (ib_result->out_sqlda == NULL || !ib_result->has_more_rows) {
1544+
if (ib_query->out_sqlda == NULL || !ib_query->has_more_rows || !ib_query->is_open) {
15411545
RETURN_FALSE;
15421546
}
15431547

1544-
if (ib_result->statement_type != isc_info_sql_stmt_exec_procedure) {
1545-
if (isc_dsql_fetch(IB_STATUS, &ib_result->stmt, 1, ib_result->out_sqlda)) {
1546-
ib_result->has_more_rows = 0;
1548+
if (ib_query->statement_type != isc_info_sql_stmt_exec_procedure) {
1549+
if (isc_dsql_fetch(IB_STATUS, &ib_query->stmt, 1, ib_query->out_sqlda)) {
1550+
ib_query->has_more_rows = 0;
1551+
ib_query->is_open = 0;
1552+
15471553
if (IB_STATUS[0] && IB_STATUS[1]) { /* error in fetch */
15481554
_php_ibase_error();
15491555
}
1556+
1557+
if(isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_close)){
1558+
_php_ibase_error();
1559+
}
1560+
15501561
RETURN_FALSE;
15511562
}
15521563
} else {
1553-
ib_result->has_more_rows = 0;
1564+
ib_query->has_more_rows = 0;
1565+
ib_query->is_open = 0;
15541566
}
15551567

1556-
array_init(return_value);
1557-
1558-
for (i = 0; i < ib_result->out_sqlda->sqld; ++i) {
1559-
XSQLVAR *var = &ib_result->out_sqlda->sqlvar[i];
1560-
char buf[METADATALENGTH+4], *alias = var->aliasname;
1561-
1562-
if (! (fetch_type & FETCH_ROW)) {
1563-
int i = 0;
1564-
char const *base = "FIELD"; /* use 'FIELD' if name is empty */
1565-
1566-
/**
1567-
* Ensure no two columns have identical names:
1568-
* keep generating new names until we find one that is unique.
1569-
*/
1570-
switch (*alias) {
1571-
void *p;
1572-
1573-
default:
1574-
i = 1;
1575-
base = alias;
1576-
1577-
while ((p = zend_symtable_str_find_ptr(
1578-
Z_ARRVAL_P(return_value), alias, strlen(alias))) != NULL) {
1568+
assert(ib_query->out_fields_count == ib_query->out_sqlda->sqld);
15791569

1580-
case '\0':
1581-
snprintf(alias = buf, sizeof(buf), "%s_%02d", base, i++);
1582-
}
1570+
HashTable *ht_ret;
1571+
if(!(fetch_type & FETCH_ROW)) {
1572+
if(!ib_query->ht_aliases){
1573+
if(_php_ibase_alloc_ht_aliases(ib_query)){
1574+
_php_ibase_error();
1575+
RETURN_FALSE;
15831576
}
15841577
}
1578+
ht_ret = zend_array_dup(ib_query->ht_aliases);
1579+
} else {
1580+
if(!ib_query->ht_ind)_php_ibase_alloc_ht_ind(ib_query);
1581+
ht_ret = zend_array_dup(ib_query->ht_ind);
1582+
}
1583+
1584+
for(i = 0; i < ib_query->out_fields_count; ++i) {
1585+
XSQLVAR *var = &ib_query->out_sqlda->sqlvar[i];
15851586

1587+
// TODO: just continue and unnest. All fields are set to NULL already
15861588
if (((var->sqltype & 1) == 0) || *var->sqlind != -1) {
1587-
zval result;
1589+
zval *result = zend_hash_get_current_data(ht_ret);
15881590

15891591
switch (var->sqltype & ~1) {
15901592

15911593
default:
1592-
_php_ibase_var_zval(&result, var->sqldata, var->sqltype, var->sqllen,
1594+
_php_ibase_var_zval(result, var->sqldata, var->sqltype, var->sqllen,
15931595
var->sqlscale, flag);
15941596
break;
15951597
case SQL_BLOB:
@@ -1604,7 +1606,7 @@ static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type)
16041606
blob_handle.bl_handle = 0;
16051607
blob_handle.bl_qd = *(ISC_QUAD *) var->sqldata;
16061608

1607-
if (isc_open_blob(IB_STATUS, &ib_result->link->handle, &ib_result->trans->handle,
1609+
if (isc_open_blob(IB_STATUS, &ib_query->link->handle, &ib_query->trans->handle,
16081610
&blob_handle.bl_handle, &blob_handle.bl_qd)) {
16091611
_php_ibase_error();
16101612
goto _php_ibase_fetch_error;
@@ -1639,8 +1641,8 @@ static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type)
16391641
}
16401642

16411643
if (max_len == 0) {
1642-
ZVAL_STRING(&result, "");
1643-
} else if (SUCCESS != _php_ibase_blob_get(&result, &blob_handle,
1644+
ZVAL_STRING(result, "");
1645+
} else if (SUCCESS != _php_ibase_blob_get(result, &blob_handle,
16441646
max_len)) {
16451647
goto _php_ibase_fetch_error;
16461648
}
@@ -1652,24 +1654,24 @@ static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type)
16521654

16531655
} else { /* blob id only */
16541656
ISC_QUAD bl_qd = *(ISC_QUAD *) var->sqldata;
1655-
ZVAL_NEW_STR(&result, _php_ibase_quad_to_string(bl_qd));
1657+
ZVAL_NEW_STR(result, _php_ibase_quad_to_string(bl_qd));
16561658
}
16571659
break;
16581660
case SQL_ARRAY:
16591661
if (flag & PHP_IBASE_FETCH_ARRAYS) { /* array can be *huge* so only fetch if asked */
16601662
ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
1661-
ibase_array *ib_array = &ib_result->out_array[array_cnt++];
1663+
ibase_array *ib_array = &ib_query->out_array[array_cnt++];
16621664
void *ar_data = emalloc(ib_array->ar_size);
16631665

1664-
if (isc_array_get_slice(IB_STATUS, &ib_result->link->handle,
1665-
&ib_result->trans->handle, &ar_qd, &ib_array->ar_desc,
1666+
if (isc_array_get_slice(IB_STATUS, &ib_query->link->handle,
1667+
&ib_query->trans->handle, &ar_qd, &ib_array->ar_desc,
16661668
ar_data, &ib_array->ar_size)) {
16671669
_php_ibase_error();
16681670
efree(ar_data);
16691671
goto _php_ibase_fetch_error;
16701672
}
16711673

1672-
if (FAILURE == _php_ibase_arr_zval(&result, ar_data, ib_array->ar_size, ib_array,
1674+
if (FAILURE == _php_ibase_arr_zval(result, ar_data, ib_array->ar_size, ib_array,
16731675
0, flag)) {
16741676
efree(ar_data);
16751677
goto _php_ibase_fetch_error;
@@ -1678,27 +1680,18 @@ static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type)
16781680

16791681
} else { /* blob id only */
16801682
ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
1681-
ZVAL_NEW_STR(&result, _php_ibase_quad_to_string(ar_qd));
1683+
ZVAL_NEW_STR(result, _php_ibase_quad_to_string(ar_qd));
16821684
}
16831685
break;
16841686
_php_ibase_fetch_error:
1685-
zval_ptr_dtor_nogc(&result);
16861687
RETURN_FALSE;
16871688
} /* switch */
1688-
1689-
if (fetch_type & FETCH_ROW) {
1690-
add_index_zval(return_value, i, &result);
1691-
} else {
1692-
add_assoc_zval(return_value, alias, &result);
1693-
}
1694-
} else {
1695-
if (fetch_type & FETCH_ROW) {
1696-
add_index_null(return_value, i);
1697-
} else {
1698-
add_assoc_null(return_value, alias);
1699-
}
17001689
}
1690+
1691+
zend_hash_move_forward(ht_ret);
17011692
} /* for field */
1693+
1694+
RETVAL_ARR(ht_ret);
17021695
}
17031696
/* }}} */
17041697

@@ -2204,4 +2197,82 @@ static int _php_ibase_get_vars_count(ibase_query *ib_query)
22042197
return rv;
22052198
}
22062199

2200+
static int _php_ibase_fetch_query_res(zval *from, ibase_query **ib_query)
2201+
{
2202+
*ib_query = zend_fetch_resource_ex(from, LE_QUERY, le_query);
2203+
2204+
if(*ib_query == NULL) {
2205+
// TODO: throw something or not? notice? warning?
2206+
php_error_docref(NULL, E_NOTICE, "query already freed");
2207+
return FAILURE;
2208+
}
2209+
2210+
return SUCCESS;
2211+
}
2212+
2213+
// We can't rely on aliasname coming from XSQLVAR if we want long field names
2214+
// (>31). We also can't rely on parsing buffer from isc_dsql_sql_info() because
2215+
// it's 32KB limit can be easily overflown with combination of long field names
2216+
// and large amounts of fields. So I added wrapper to use newer API but that
2217+
// also require runtime fbclient > 40 hence the runtime checks. Ideally rewrite
2218+
// everything using newer API but that's a bit of work.
2219+
static int _php_ibase_alloc_ht_aliases(ibase_query *ib_query)
2220+
{
2221+
ALLOC_HASHTABLE(ib_query->ht_aliases);
2222+
zend_hash_init(ib_query->ht_aliases, ib_query->out_fields_count, NULL, ZVAL_PTR_DTOR, 0);
2223+
2224+
#if FB_API_VER >= 40
2225+
if(IBG(fb_get_master_interface) && IBG(fb_get_statement_interface)) {
2226+
if(fb_insert_aliases(IB_STATUS, ib_query)){
2227+
return FAILURE;
2228+
}
2229+
} else {
2230+
#endif
2231+
// Old API
2232+
for(size_t i = 0; i < ib_query->out_fields_count; i++){
2233+
XSQLVAR *var = &ib_query->out_sqlda->sqlvar[i];
2234+
2235+
_php_ibase_insert_alias(ib_query->ht_aliases,
2236+
var->aliasname, MIN(31, var->aliasname_length));
2237+
}
2238+
#if FB_API_VER >= 40
2239+
}
2240+
#endif
2241+
2242+
return SUCCESS;
2243+
}
2244+
2245+
static void _php_ibase_alloc_ht_ind(ibase_query *ib_query)
2246+
{
2247+
ALLOC_HASHTABLE(ib_query->ht_ind);
2248+
zend_hash_init(ib_query->ht_ind, ib_query->out_fields_count, NULL, ZVAL_PTR_DTOR, 0);
2249+
2250+
zval t2;
2251+
ZVAL_NULL(&t2);
2252+
2253+
for(size_t i = 0; i < ib_query->out_fields_count; i++) {
2254+
zend_hash_index_add(ib_query->ht_ind, i, &t2);
2255+
}
2256+
}
2257+
2258+
static void _php_ibase_free_query_impl(INTERNAL_FUNCTION_PARAMETERS)
2259+
{
2260+
zval *query_arg;
2261+
ibase_query *ib_query;
2262+
2263+
RESET_ERRMSG;
2264+
2265+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &query_arg) == FAILURE) {
2266+
return;
2267+
}
2268+
2269+
if(_php_ibase_fetch_query_res(query_arg, &ib_query)) {
2270+
return;
2271+
}
2272+
2273+
zend_list_close(Z_RES_P(query_arg));
2274+
2275+
RETURN_TRUE;
2276+
}
2277+
22072278
#endif /* HAVE_IBASE */

php_ibase_includes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ extern "C" {
255255

256256
void _php_ibase_insert_alias(HashTable *ht, const char *alias, size_t alias_len);
257257
static int _php_ibase_get_vars_count(ibase_query *ib_query);
258+
static int _php_ibase_fetch_query_res(zval *from, ibase_query **ib_query);
259+
static int _php_ibase_alloc_ht_aliases(ibase_query *ib_query);
260+
static void _php_ibase_alloc_ht_ind(ibase_query *ib_query);
258261

259262
#ifdef __cplusplus
260263
}

0 commit comments

Comments
 (0)