Skip to content

Commit 91c1393

Browse files
committed
Fixes
1 parent 5c4cabc commit 91c1393

6 files changed

+144
-82
lines changed

ext/odbc/php_odbc.c

Lines changed: 91 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,18 @@
6565

6666
void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent);
6767
static void safe_odbc_disconnect(void *handle);
68+
static void close_results_with_connection(const odbc_connection *conn);
6869

6970
static int le_pconn;
7071

7172
static zend_class_entry *odbc_connection_ce, *odbc_result_ce;
7273
static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_handlers;
7374

75+
static void odbc_insert_new_result(zval *result) {
76+
Z_TRY_ADDREF_P(result);
77+
zend_hash_next_index_insert_new(&ODBCG(results), result);
78+
}
79+
7480
static inline odbc_link *odbc_link_from_obj(zend_object *obj) {
7581
return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std));
7682
}
@@ -95,19 +101,29 @@ static zend_function *odbc_connection_get_constructor(zend_object *object) {
95101

96102
static void odbc_link_free(odbc_link *link)
97103
{
98-
/* If aborted via timer expiration, don't try to call any unixODBC function */
99-
if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) {
100-
safe_odbc_disconnect(link->connection->hdbc);
101-
SQLFreeConnect(link->connection->hdbc);
102-
SQLFreeEnv(link->connection->henv);
103-
}
104-
efree(link->connection);
105-
link->connection = NULL;
106-
ODBCG(num_links)--;
107-
if (!link->persistent) {
104+
ZEND_ASSERT(link->connection && "link has already been closed");
105+
106+
if (link->persistent) {
107+
zend_hash_del(&EG(persistent_list), link->hash);
108+
} else {
109+
close_results_with_connection(link->connection);
110+
108111
zend_hash_del(&ODBCG(connections), link->hash);
112+
113+
/* If aborted via timer expiration, don't try to call any unixODBC function */
114+
if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) {
115+
safe_odbc_disconnect(link->connection->hdbc);
116+
SQLFreeConnect(link->connection->hdbc);
117+
SQLFreeEnv(link->connection->henv);
118+
}
119+
efree(link->connection);
120+
ODBCG(num_links)--;
109121
}
122+
123+
link->connection = NULL;
124+
110125
zend_string_release(link->hash);
126+
link->hash = NULL;
111127
}
112128

113129
static void odbc_connection_free_obj(zend_object *obj)
@@ -146,6 +162,8 @@ static zend_function *odbc_result_get_constructor(zend_object *object) {
146162

147163
static void odbc_result_free(odbc_result *res)
148164
{
165+
ZEND_ASSERT(res->conn_ptr && "result has already been closed");
166+
149167
if (res->values) {
150168
for (int i = 0; i < res->numcols; i++) {
151169
if (res->values[i].value) {
@@ -154,6 +172,7 @@ static void odbc_result_free(odbc_result *res)
154172
}
155173
efree(res->values);
156174
res->values = NULL;
175+
res->numcols = 0;
157176
}
158177
/* If aborted via timer expiration, don't try to call any unixODBC function */
159178
if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) {
@@ -165,21 +184,33 @@ static void odbc_result_free(odbc_result *res)
165184
/* We don't want the connection to be closed after the last statement has been closed
166185
* Connections will be closed on shutdown
167186
*/
187+
res->stmt = NULL;
168188
}
169189
if (res->param_info) {
170190
efree(res->param_info);
191+
res->param_info = NULL;
171192
}
172-
efree(res);
193+
res->conn_ptr = NULL;
173194
}
174195

175196
static void odbc_result_free_obj(zend_object *obj) {
197+
zend_ulong num_index;
198+
zval *p;
199+
176200
odbc_result *result = odbc_result_from_obj(obj);
177201

178-
if (!result->stmt) {
202+
if (!result->conn_ptr) {
179203
zend_object_std_dtor(&result->std);
180204
return;
181205
}
182206

207+
ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) {
208+
odbc_result *res = Z_ODBC_RESULT_P(p);
209+
if (res->stmt == result->stmt) {
210+
zend_hash_index_del(&ODBCG(results), num_index);
211+
}
212+
} ZEND_HASH_FOREACH_END();
213+
183214
odbc_result_free(result);
184215
zend_object_std_dtor(&result->std);
185216
}
@@ -223,7 +254,7 @@ static void close_results_with_connection(const odbc_connection *conn) {
223254
ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) {
224255
odbc_result *result = Z_ODBC_RESULT_P(p);
225256
if (result->conn_ptr == conn) {
226-
odbc_result_free((odbc_result*) p);
257+
odbc_result_free(result);
227258
zend_hash_index_del(&ODBCG(results), num_index);
228259
}
229260
} ZEND_HASH_FOREACH_END();
@@ -256,6 +287,7 @@ static void _close_odbc_pconn(zend_resource *rsrc)
256287
SQLFreeEnv(conn->henv);
257288
}
258289
free(conn);
290+
conn = NULL;
259291

260292
ODBCG(num_links)--;
261293
ODBCG(num_persistent)--;
@@ -812,30 +844,38 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
812844
/* {{{ Close all ODBC connections */
813845
PHP_FUNCTION(odbc_close_all)
814846
{
815-
zval *p;
847+
odbc_link *p;
848+
zval *zv;
816849

817850
if (zend_parse_parameters_none() == FAILURE) {
818851
RETURN_THROWS();
819852
}
820853

821-
/* Loop through list and close all statements */
822-
ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) {
823-
odbc_result_free((odbc_result*) p);
854+
/* Loop through the connection list, now close all non-persistent connections and their results */
855+
ZEND_HASH_FOREACH_PTR(&ODBCG(connections), p) {
856+
if (p->connection) {
857+
odbc_link_free(p);
858+
}
824859
} ZEND_HASH_FOREACH_END();
825860

826-
zend_hash_clean(&ODBCG(results));
861+
zend_hash_clean(&ODBCG(connections));
827862

828-
/* Second loop through list, now close all non-persistent connections */
829-
ZEND_HASH_FOREACH_VAL(&ODBCG(connections), p) {
830-
odbc_link_free((odbc_link*) p);
863+
/* Loop through the persistent list, now close all persistent connections and their results */
864+
ZEND_HASH_FOREACH_VAL(&EG(persistent_list), zv) {
865+
if (Z_RES_P(zv)->type == le_pconn) {
866+
zend_list_close(Z_RES_P(zv));
867+
}
831868
} ZEND_HASH_FOREACH_END();
832869

833-
/* Third loop through persistent list, now close all persistent connections */
834-
ZEND_HASH_FOREACH_VAL(&EG(persistent_list), p) {
835-
if (Z_RES_P(p)->type == le_pconn) {
836-
zend_list_close(Z_RES_P(p));
870+
/* Loop through the results list searching for any dangling results and close all statements */
871+
ZEND_HASH_FOREACH_VAL(&ODBCG(results), zv) {
872+
odbc_result *result = Z_ODBC_RESULT_P(zv);
873+
if (result->conn_ptr) {
874+
odbc_result_free(result);
837875
}
838876
} ZEND_HASH_FOREACH_END();
877+
878+
zend_hash_clean(&ODBCG(results));
839879
}
840880
/* }}} */
841881

@@ -947,7 +987,7 @@ PHP_FUNCTION(odbc_prepare)
947987
}
948988
}
949989

950-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
990+
odbc_insert_new_result(return_value);
951991
}
952992
/* }}} */
953993

@@ -1323,7 +1363,7 @@ PHP_FUNCTION(odbc_exec)
13231363
result->conn_ptr = conn;
13241364
result->fetched = 0;
13251365

1326-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
1366+
odbc_insert_new_result(return_value);
13271367
}
13281368
/* }}} */
13291369

@@ -1390,7 +1430,6 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
13901430
else
13911431
#endif
13921432
result->fetched++;
1393-
}
13941433

13951434
for(i = 0; i < result->numcols; i++) {
13961435
sql_c_type = SQL_C_CHAR;
@@ -1500,7 +1539,7 @@ PHP_FUNCTION(odbc_fetch_into)
15001539
SQLSMALLINT sql_c_type;
15011540
char *buf = NULL;
15021541
zval *pv_res, *pv_res_arr, tmp;
1503-
zend_long pv_row = 0;
1542+
zend_long pv_row = -1;
15041543
bool pv_row_is_null = true;
15051544
#ifdef HAVE_SQL_EXTENDED_FETCH
15061545
SQLULEN crow;
@@ -1553,7 +1592,6 @@ PHP_FUNCTION(odbc_fetch_into)
15531592
else
15541593
#endif
15551594
result->fetched++;
1556-
}
15571595

15581596
for(i = 0; i < result->numcols; i++) {
15591597
sql_c_type = SQL_C_CHAR;
@@ -1630,7 +1668,7 @@ PHP_FUNCTION(odbc_fetch_row)
16301668
odbc_result *result;
16311669
RETCODE rc;
16321670
zval *pv_res;
1633-
zend_long pv_row = 0;
1671+
zend_long pv_row = -1;
16341672
bool pv_row_is_null = true;
16351673
#ifdef HAVE_SQL_EXTENDED_FETCH
16361674
SQLULEN crow;
@@ -1674,6 +1712,7 @@ PHP_FUNCTION(odbc_fetch_row)
16741712
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
16751713
RETURN_FALSE;
16761714
}
1715+
16771716
#ifdef HAVE_SQL_EXTENDED_FETCH
16781717
if (!pv_row_is_null) {
16791718
result->fetched = (SQLLEN)pv_row;
@@ -2042,7 +2081,6 @@ PHP_FUNCTION(odbc_free_result)
20422081
{
20432082
zval *pv_res;
20442083
odbc_result *result;
2045-
int i;
20462084

20472085
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) {
20482086
RETURN_THROWS();
@@ -2051,18 +2089,10 @@ PHP_FUNCTION(odbc_free_result)
20512089
result = Z_ODBC_RESULT_P(pv_res);
20522090
CHECK_ODBC_RESULT(result);
20532091

2054-
if (result->values) {
2055-
for (i = 0; i < result->numcols; i++) {
2056-
if (result->values[i].value) {
2057-
efree(result->values[i].value);
2058-
}
2059-
}
2060-
efree(result->values);
2061-
result->values = NULL;
2092+
if (result->conn_ptr) {
2093+
odbc_result_free(result);
20622094
}
20632095

2064-
zend_list_close(Z_RES_P(pv_res));
2065-
20662096
RETURN_TRUE;
20672097
}
20682098
/* }}} */
@@ -2085,6 +2115,7 @@ PHP_FUNCTION(odbc_pconnect)
20852115
bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool persistent, zend_string *hash)
20862116
{
20872117
RETCODE rc;
2118+
SQLRETURN ret;
20882119
odbc_link *link;
20892120

20902121
object_init_ex(zv, odbc_connection_ce);
@@ -2093,9 +2124,18 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool
20932124
memset(link->connection, 0, sizeof(odbc_connection));
20942125

20952126
link->persistent = persistent;
2096-
link->hash = hash;
2097-
SQLAllocEnv(link->connection->henv);
2098-
SQLAllocConnect(link->connection->henv, link->connection->hdbc);
2127+
link->hash = zend_string_copy(hash);
2128+
ret = SQLAllocEnv(&((*link->connection).henv));
2129+
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
2130+
odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLAllocEnv");
2131+
return false;
2132+
}
2133+
2134+
ret = SQLAllocConnect((*link->connection).henv, &((*link->connection).hdbc));
2135+
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
2136+
odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLAllocConnect");
2137+
return false;
2138+
}
20992139

21002140
#if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
21012141
SQLSetConnectOption((link->connection->hdbc, SQL_TRANSLATE_OPTION,
@@ -2358,9 +2398,9 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
23582398
RETURN_FALSE;
23592399
}
23602400
ODBCG(num_links)++;
2401+
zend_hash_update_ptr(&ODBCG(connections), hashed_details.s, Z_ODBC_LINK_P(return_value));
23612402
}
23622403

2363-
zend_hash_update(&ODBCG(connections), hashed_details.s, return_value);
23642404
smart_str_free(&hashed_details);
23652405
}
23662406
/* }}} */
@@ -2378,12 +2418,6 @@ PHP_FUNCTION(odbc_close)
23782418
link = Z_ODBC_LINK_P(pv_conn);
23792419
CHECK_ODBC_CONNECTION(link->connection);
23802420

2381-
if (link->persistent) {
2382-
zend_hash_del(&EG(persistent_list), link->hash);
2383-
}
2384-
2385-
close_results_with_connection(link->connection);
2386-
23872421
odbc_link_free(link);
23882422
}
23892423
/* }}} */
@@ -2815,7 +2849,7 @@ PHP_FUNCTION(odbc_tables)
28152849
result->conn_ptr = conn;
28162850
result->fetched = 0;
28172851

2818-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
2852+
odbc_insert_new_result(return_value);
28192853
}
28202854
/* }}} */
28212855

@@ -2883,7 +2917,7 @@ PHP_FUNCTION(odbc_columns)
28832917
result->conn_ptr = conn;
28842918
result->fetched = 0;
28852919

2886-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
2920+
odbc_insert_new_result(return_value);
28872921
}
28882922
/* }}} */
28892923

@@ -2945,7 +2979,7 @@ PHP_FUNCTION(odbc_columnprivileges)
29452979
result->conn_ptr = conn;
29462980
result->fetched = 0;
29472981

2948-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
2982+
odbc_insert_new_result(return_value);
29492983
}
29502984
/* }}} */
29512985
#endif /* HAVE_DBMAKER || HAVE_SOLID*/
@@ -3022,7 +3056,7 @@ PHP_FUNCTION(odbc_foreignkeys)
30223056
result->conn_ptr = conn;
30233057
result->fetched = 0;
30243058

3025-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
3059+
odbc_insert_new_result(return_value);
30263060
}
30273061
/* }}} */
30283062
#endif /* HAVE_SOLID */
@@ -3081,7 +3115,7 @@ PHP_FUNCTION(odbc_gettypeinfo)
30813115
result->conn_ptr = conn;
30823116
result->fetched = 0;
30833117

3084-
zend_hash_next_index_insert_new(&ODBCG(results), return_value);
3118+
odbc_insert_new_result(return_value);
30853119
}
30863120
/* }}} */
30873121

ext/odbc/tests/bug78470.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ $conn = odbc_connect($dsn, $user, $pass);
1212
var_dump(odbc_specialcolumns($conn, SQL_BEST_ROWID, '', '', '', SQL_SCOPE_CURROW, SQL_NO_NULLS));
1313
?>
1414
--EXPECTF--
15-
resource(%d) of type (odbc result)
15+
object(ODBC\Result)#%d (%d) {
16+
}

0 commit comments

Comments
 (0)