65
65
66
66
void odbc_do_connect (INTERNAL_FUNCTION_PARAMETERS , int persistent );
67
67
static void safe_odbc_disconnect (void * handle );
68
+ static void close_results_with_connection (const odbc_connection * conn );
68
69
69
70
static int le_pconn ;
70
71
71
72
static zend_class_entry * odbc_connection_ce , * odbc_result_ce ;
72
73
static zend_object_handlers odbc_connection_object_handlers , odbc_result_object_handlers ;
73
74
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
+
74
80
static inline odbc_link * odbc_link_from_obj (zend_object * obj ) {
75
81
return (odbc_link * )((char * )(obj ) - XtOffsetOf (odbc_link , std ));
76
82
}
@@ -95,19 +101,29 @@ static zend_function *odbc_connection_get_constructor(zend_object *object) {
95
101
96
102
static void odbc_link_free (odbc_link * link )
97
103
{
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
+
108
111
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 )-- ;
109
121
}
122
+
123
+ link -> connection = NULL ;
124
+
110
125
zend_string_release (link -> hash );
126
+ link -> hash = NULL ;
111
127
}
112
128
113
129
static void odbc_connection_free_obj (zend_object * obj )
@@ -146,6 +162,8 @@ static zend_function *odbc_result_get_constructor(zend_object *object) {
146
162
147
163
static void odbc_result_free (odbc_result * res )
148
164
{
165
+ ZEND_ASSERT (res -> conn_ptr && "result has already been closed" );
166
+
149
167
if (res -> values ) {
150
168
for (int i = 0 ; i < res -> numcols ; i ++ ) {
151
169
if (res -> values [i ].value ) {
@@ -154,6 +172,7 @@ static void odbc_result_free(odbc_result *res)
154
172
}
155
173
efree (res -> values );
156
174
res -> values = NULL ;
175
+ res -> numcols = 0 ;
157
176
}
158
177
/* If aborted via timer expiration, don't try to call any unixODBC function */
159
178
if (res -> stmt && !(PG (connection_status ) & PHP_CONNECTION_TIMEOUT )) {
@@ -165,21 +184,33 @@ static void odbc_result_free(odbc_result *res)
165
184
/* We don't want the connection to be closed after the last statement has been closed
166
185
* Connections will be closed on shutdown
167
186
*/
187
+ res -> stmt = NULL ;
168
188
}
169
189
if (res -> param_info ) {
170
190
efree (res -> param_info );
191
+ res -> param_info = NULL ;
171
192
}
172
- efree ( res ) ;
193
+ res -> conn_ptr = NULL ;
173
194
}
174
195
175
196
static void odbc_result_free_obj (zend_object * obj ) {
197
+ zend_ulong num_index ;
198
+ zval * p ;
199
+
176
200
odbc_result * result = odbc_result_from_obj (obj );
177
201
178
- if (!result -> stmt ) {
202
+ if (!result -> conn_ptr ) {
179
203
zend_object_std_dtor (& result -> std );
180
204
return ;
181
205
}
182
206
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
+
183
214
odbc_result_free (result );
184
215
zend_object_std_dtor (& result -> std );
185
216
}
@@ -223,7 +254,7 @@ static void close_results_with_connection(const odbc_connection *conn) {
223
254
ZEND_HASH_FOREACH_NUM_KEY_VAL (& ODBCG (results ), num_index , p ) {
224
255
odbc_result * result = Z_ODBC_RESULT_P (p );
225
256
if (result -> conn_ptr == conn ) {
226
- odbc_result_free (( odbc_result * ) p );
257
+ odbc_result_free (result );
227
258
zend_hash_index_del (& ODBCG (results ), num_index );
228
259
}
229
260
} ZEND_HASH_FOREACH_END ();
@@ -256,6 +287,7 @@ static void _close_odbc_pconn(zend_resource *rsrc)
256
287
SQLFreeEnv (conn -> henv );
257
288
}
258
289
free (conn );
290
+ conn = NULL ;
259
291
260
292
ODBCG (num_links )-- ;
261
293
ODBCG (num_persistent )-- ;
@@ -812,30 +844,38 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
812
844
/* {{{ Close all ODBC connections */
813
845
PHP_FUNCTION (odbc_close_all )
814
846
{
815
- zval * p ;
847
+ odbc_link * p ;
848
+ zval * zv ;
816
849
817
850
if (zend_parse_parameters_none () == FAILURE ) {
818
851
RETURN_THROWS ();
819
852
}
820
853
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
+ }
824
859
} ZEND_HASH_FOREACH_END ();
825
860
826
- zend_hash_clean (& ODBCG (results ));
861
+ zend_hash_clean (& ODBCG (connections ));
827
862
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
+ }
831
868
} ZEND_HASH_FOREACH_END ();
832
869
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 );
837
875
}
838
876
} ZEND_HASH_FOREACH_END ();
877
+
878
+ zend_hash_clean (& ODBCG (results ));
839
879
}
840
880
/* }}} */
841
881
@@ -947,7 +987,7 @@ PHP_FUNCTION(odbc_prepare)
947
987
}
948
988
}
949
989
950
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
990
+ odbc_insert_new_result ( return_value );
951
991
}
952
992
/* }}} */
953
993
@@ -1323,7 +1363,7 @@ PHP_FUNCTION(odbc_exec)
1323
1363
result -> conn_ptr = conn ;
1324
1364
result -> fetched = 0 ;
1325
1365
1326
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
1366
+ odbc_insert_new_result ( return_value );
1327
1367
}
1328
1368
/* }}} */
1329
1369
@@ -1390,7 +1430,6 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
1390
1430
else
1391
1431
#endif
1392
1432
result -> fetched ++ ;
1393
- }
1394
1433
1395
1434
for (i = 0 ; i < result -> numcols ; i ++ ) {
1396
1435
sql_c_type = SQL_C_CHAR ;
@@ -1500,7 +1539,7 @@ PHP_FUNCTION(odbc_fetch_into)
1500
1539
SQLSMALLINT sql_c_type ;
1501
1540
char * buf = NULL ;
1502
1541
zval * pv_res , * pv_res_arr , tmp ;
1503
- zend_long pv_row = 0 ;
1542
+ zend_long pv_row = -1 ;
1504
1543
bool pv_row_is_null = true;
1505
1544
#ifdef HAVE_SQL_EXTENDED_FETCH
1506
1545
SQLULEN crow ;
@@ -1553,7 +1592,6 @@ PHP_FUNCTION(odbc_fetch_into)
1553
1592
else
1554
1593
#endif
1555
1594
result -> fetched ++ ;
1556
- }
1557
1595
1558
1596
for (i = 0 ; i < result -> numcols ; i ++ ) {
1559
1597
sql_c_type = SQL_C_CHAR ;
@@ -1630,7 +1668,7 @@ PHP_FUNCTION(odbc_fetch_row)
1630
1668
odbc_result * result ;
1631
1669
RETCODE rc ;
1632
1670
zval * pv_res ;
1633
- zend_long pv_row = 0 ;
1671
+ zend_long pv_row = -1 ;
1634
1672
bool pv_row_is_null = true;
1635
1673
#ifdef HAVE_SQL_EXTENDED_FETCH
1636
1674
SQLULEN crow ;
@@ -1674,6 +1712,7 @@ PHP_FUNCTION(odbc_fetch_row)
1674
1712
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
1675
1713
RETURN_FALSE ;
1676
1714
}
1715
+
1677
1716
#ifdef HAVE_SQL_EXTENDED_FETCH
1678
1717
if (!pv_row_is_null ) {
1679
1718
result -> fetched = (SQLLEN )pv_row ;
@@ -2042,7 +2081,6 @@ PHP_FUNCTION(odbc_free_result)
2042
2081
{
2043
2082
zval * pv_res ;
2044
2083
odbc_result * result ;
2045
- int i ;
2046
2084
2047
2085
if (zend_parse_parameters (ZEND_NUM_ARGS (), "O" , & pv_res , odbc_result_ce ) == FAILURE ) {
2048
2086
RETURN_THROWS ();
@@ -2051,18 +2089,10 @@ PHP_FUNCTION(odbc_free_result)
2051
2089
result = Z_ODBC_RESULT_P (pv_res );
2052
2090
CHECK_ODBC_RESULT (result );
2053
2091
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 );
2062
2094
}
2063
2095
2064
- zend_list_close (Z_RES_P (pv_res ));
2065
-
2066
2096
RETURN_TRUE ;
2067
2097
}
2068
2098
/* }}} */
@@ -2085,6 +2115,7 @@ PHP_FUNCTION(odbc_pconnect)
2085
2115
bool odbc_sqlconnect (zval * zv , char * db , char * uid , char * pwd , int cur_opt , bool persistent , zend_string * hash )
2086
2116
{
2087
2117
RETCODE rc ;
2118
+ SQLRETURN ret ;
2088
2119
odbc_link * link ;
2089
2120
2090
2121
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
2093
2124
memset (link -> connection , 0 , sizeof (odbc_connection ));
2094
2125
2095
2126
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
+ }
2099
2139
2100
2140
#if defined(HAVE_SOLID ) || defined(HAVE_SOLID_30 )
2101
2141
SQLSetConnectOption ((link -> connection -> hdbc , SQL_TRANSLATE_OPTION ,
@@ -2358,9 +2398,9 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
2358
2398
RETURN_FALSE ;
2359
2399
}
2360
2400
ODBCG (num_links )++ ;
2401
+ zend_hash_update_ptr (& ODBCG (connections ), hashed_details .s , Z_ODBC_LINK_P (return_value ));
2361
2402
}
2362
2403
2363
- zend_hash_update (& ODBCG (connections ), hashed_details .s , return_value );
2364
2404
smart_str_free (& hashed_details );
2365
2405
}
2366
2406
/* }}} */
@@ -2378,12 +2418,6 @@ PHP_FUNCTION(odbc_close)
2378
2418
link = Z_ODBC_LINK_P (pv_conn );
2379
2419
CHECK_ODBC_CONNECTION (link -> connection );
2380
2420
2381
- if (link -> persistent ) {
2382
- zend_hash_del (& EG (persistent_list ), link -> hash );
2383
- }
2384
-
2385
- close_results_with_connection (link -> connection );
2386
-
2387
2421
odbc_link_free (link );
2388
2422
}
2389
2423
/* }}} */
@@ -2815,7 +2849,7 @@ PHP_FUNCTION(odbc_tables)
2815
2849
result -> conn_ptr = conn ;
2816
2850
result -> fetched = 0 ;
2817
2851
2818
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
2852
+ odbc_insert_new_result ( return_value );
2819
2853
}
2820
2854
/* }}} */
2821
2855
@@ -2883,7 +2917,7 @@ PHP_FUNCTION(odbc_columns)
2883
2917
result -> conn_ptr = conn ;
2884
2918
result -> fetched = 0 ;
2885
2919
2886
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
2920
+ odbc_insert_new_result ( return_value );
2887
2921
}
2888
2922
/* }}} */
2889
2923
@@ -2945,7 +2979,7 @@ PHP_FUNCTION(odbc_columnprivileges)
2945
2979
result -> conn_ptr = conn ;
2946
2980
result -> fetched = 0 ;
2947
2981
2948
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
2982
+ odbc_insert_new_result ( return_value );
2949
2983
}
2950
2984
/* }}} */
2951
2985
#endif /* HAVE_DBMAKER || HAVE_SOLID*/
@@ -3022,7 +3056,7 @@ PHP_FUNCTION(odbc_foreignkeys)
3022
3056
result -> conn_ptr = conn ;
3023
3057
result -> fetched = 0 ;
3024
3058
3025
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
3059
+ odbc_insert_new_result ( return_value );
3026
3060
}
3027
3061
/* }}} */
3028
3062
#endif /* HAVE_SOLID */
@@ -3081,7 +3115,7 @@ PHP_FUNCTION(odbc_gettypeinfo)
3081
3115
result -> conn_ptr = conn ;
3082
3116
result -> fetched = 0 ;
3083
3117
3084
- zend_hash_next_index_insert_new ( & ODBCG ( results ), return_value );
3118
+ odbc_insert_new_result ( return_value );
3085
3119
}
3086
3120
/* }}} */
3087
3121
0 commit comments