xref: /PHP-5.3/ext/odbc/php_odbc.c (revision adc070ca)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Stig S�ther Bakken <ssb@php.net>                            |
16    |          Andreas Karajannis <Andreas.Karajannis@gmd.de>              |
17    |          Frank M. Kromann <frank@kromann.info>  Support for DB/2 CLI |
18    |          Kevin N. Shallow <kshallow@tampabay.rr.com> Birdstep Support|
19    |          Daniel R. Kalowsky <kalowsky@php.net>                       |
20    +----------------------------------------------------------------------+
21 */
22 
23 /* $Id$ */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "php.h"
30 #include "php_globals.h"
31 
32 #include "ext/standard/info.h"
33 #include "ext/standard/php_string.h"
34 #include "ext/standard/php_standard.h"
35 
36 #include "php_odbc.h"
37 #include "php_odbc_includes.h"
38 #include "php_globals.h"
39 
40 #if HAVE_UODBC
41 
42 #include <fcntl.h>
43 #include "ext/standard/head.h"
44 #include "php_ini.h"
45 
46 #ifdef PHP_WIN32
47 #include <winsock2.h>
48 
49 #define ODBC_TYPE "Win32"
50 #define PHP_ODBC_TYPE ODBC_TYPE
51 
52 #endif
53 
54 /*
55  * not defined elsewhere
56  */
57 
58 #ifndef TRUE
59 #define TRUE 1
60 #define FALSE 0
61 #endif
62 
63 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent);
64 
65 static int le_result, le_conn, le_pconn;
66 
67 #define SAFE_SQL_NTS(n) ((SQLSMALLINT) ((n)?(SQL_NTS):0))
68 
69 /* {{{ arginfo */
70 ZEND_BEGIN_ARG_INFO(arginfo_odbc_close_all, 0)
71 ZEND_END_ARG_INFO()
72 
73 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_binmode, 0, 0, 2)
74 	ZEND_ARG_INFO(0, result_id)
75 	ZEND_ARG_INFO(0, mode)
76 ZEND_END_ARG_INFO()
77 
78 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_longreadlen, 0, 0, 2)
79 	ZEND_ARG_INFO(0, result_id)
80 	ZEND_ARG_INFO(0, length)
81 ZEND_END_ARG_INFO()
82 
83 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_prepare, 0, 0, 2)
84 	ZEND_ARG_INFO(0, connection_id)
85 	ZEND_ARG_INFO(0, query)
86 ZEND_END_ARG_INFO()
87 
88 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_execute, 0, 0, 1)
89 	ZEND_ARG_INFO(0, result_id)
90 	ZEND_ARG_INFO(0, parameters_array)
91 ZEND_END_ARG_INFO()
92 
93 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_cursor, 0, 0, 1)
94 	ZEND_ARG_INFO(0, result_id)
95 ZEND_END_ARG_INFO()
96 
97 #ifdef HAVE_SQLDATASOURCES
98 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_data_source, 0, 0, 2)
99 	ZEND_ARG_INFO(0, connection_id)
100 	ZEND_ARG_INFO(0, fetch_type)
101 ZEND_END_ARG_INFO()
102 #endif
103 
104 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_exec, 0, 0, 2)
105 	ZEND_ARG_INFO(0, connection_id)
106 	ZEND_ARG_INFO(0, query)
107 	ZEND_ARG_INFO(0, flags)
108 ZEND_END_ARG_INFO()
109 
110 #ifdef PHP_ODBC_HAVE_FETCH_HASH
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_object, 0, 0, 1)
112 	ZEND_ARG_INFO(0, result)
113 	ZEND_ARG_INFO(0, rownumber)
114 ZEND_END_ARG_INFO()
115 
116 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_array, 0, 0, 1)
117 	ZEND_ARG_INFO(0, result)
118 	ZEND_ARG_INFO(0, rownumber)
119 ZEND_END_ARG_INFO()
120 #endif
121 
122 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_into, 0, 0, 2)
123 	ZEND_ARG_INFO(0, result_id)
124 	ZEND_ARG_INFO(1, result_array)
125 	ZEND_ARG_INFO(0, rownumber)
126 ZEND_END_ARG_INFO()
127 
128 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_row, 0, 0, 1)
129 	ZEND_ARG_INFO(0, result_id)
130 	ZEND_ARG_INFO(0, row_number)
131 ZEND_END_ARG_INFO()
132 
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_result, 0, 0, 2)
134 	ZEND_ARG_INFO(0, result_id)
135 	ZEND_ARG_INFO(0, field)
136 ZEND_END_ARG_INFO()
137 
138 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_result_all, 0, 0, 1)
139 	ZEND_ARG_INFO(0, result_id)
140 	ZEND_ARG_INFO(0, format)
141 ZEND_END_ARG_INFO()
142 
143 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_free_result, 0, 0, 1)
144 	ZEND_ARG_INFO(0, result_id)
145 ZEND_END_ARG_INFO()
146 
147 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_connect, 0, 0, 3)
148 	ZEND_ARG_INFO(0, dsn)
149 	ZEND_ARG_INFO(0, user)
150 	ZEND_ARG_INFO(0, password)
151 	ZEND_ARG_INFO(0, cursor_option)
152 ZEND_END_ARG_INFO()
153 
154 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_pconnect, 0, 0, 3)
155 	ZEND_ARG_INFO(0, dsn)
156 	ZEND_ARG_INFO(0, user)
157 	ZEND_ARG_INFO(0, password)
158 	ZEND_ARG_INFO(0, cursor_option)
159 ZEND_END_ARG_INFO()
160 
161 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_close, 0, 0, 1)
162 	ZEND_ARG_INFO(0, connection_id)
163 ZEND_END_ARG_INFO()
164 
165 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_num_rows, 0, 0, 1)
166 	ZEND_ARG_INFO(0, result_id)
167 ZEND_END_ARG_INFO()
168 
169 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
170 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_next_result, 0, 0, 1)
171 	ZEND_ARG_INFO(0, result_id)
172 ZEND_END_ARG_INFO()
173 #endif
174 
175 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_num_fields, 0, 0, 1)
176 	ZEND_ARG_INFO(0, result_id)
177 ZEND_END_ARG_INFO()
178 
179 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_name, 0, 0, 2)
180 	ZEND_ARG_INFO(0, result_id)
181 	ZEND_ARG_INFO(0, field_number)
182 ZEND_END_ARG_INFO()
183 
184 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_type, 0, 0, 2)
185 	ZEND_ARG_INFO(0, result_id)
186 	ZEND_ARG_INFO(0, field_number)
187 ZEND_END_ARG_INFO()
188 
189 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_len, 0, 0, 2)
190 	ZEND_ARG_INFO(0, result_id)
191 	ZEND_ARG_INFO(0, field_number)
192 ZEND_END_ARG_INFO()
193 
194 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_scale, 0, 0, 2)
195 	ZEND_ARG_INFO(0, result_id)
196 	ZEND_ARG_INFO(0, field_number)
197 ZEND_END_ARG_INFO()
198 
199 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_num, 0, 0, 2)
200 	ZEND_ARG_INFO(0, result_id)
201 	ZEND_ARG_INFO(0, field_name)
202 ZEND_END_ARG_INFO()
203 
204 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_autocommit, 0, 0, 1)
205 	ZEND_ARG_INFO(0, connection_id)
206 	ZEND_ARG_INFO(0, onoff)
207 ZEND_END_ARG_INFO()
208 
209 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_commit, 0, 0, 1)
210 	ZEND_ARG_INFO(0, connection_id)
211 ZEND_END_ARG_INFO()
212 
213 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_rollback, 0, 0, 1)
214 	ZEND_ARG_INFO(0, connection_id)
215 ZEND_END_ARG_INFO()
216 
217 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_error, 0, 0, 0)
218 	ZEND_ARG_INFO(0, connection_id)
219 ZEND_END_ARG_INFO()
220 
221 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_errormsg, 0, 0, 0)
222 	ZEND_ARG_INFO(0, connection_id)
223 ZEND_END_ARG_INFO()
224 
225 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_setoption, 0, 0, 4)
226 	ZEND_ARG_INFO(0, conn_id)
227 	ZEND_ARG_INFO(0, which)
228 	ZEND_ARG_INFO(0, option)
229 	ZEND_ARG_INFO(0, value)
230 ZEND_END_ARG_INFO()
231 
232 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tables, 0, 0, 1)
233 	ZEND_ARG_INFO(0, connection_id)
234 	ZEND_ARG_INFO(0, qualifier)
235 	ZEND_ARG_INFO(0, owner)
236 	ZEND_ARG_INFO(0, name)
237 	ZEND_ARG_INFO(0, table_types)
238 ZEND_END_ARG_INFO()
239 
240 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columns, 0, 0, 1)
241 	ZEND_ARG_INFO(0, connection_id)
242 	ZEND_ARG_INFO(0, qualifier)
243 	ZEND_ARG_INFO(0, owner)
244 	ZEND_ARG_INFO(0, table_name)
245 	ZEND_ARG_INFO(0, column_name)
246 ZEND_END_ARG_INFO()
247 
248 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_gettypeinfo, 0, 0, 1)
249 	ZEND_ARG_INFO(0, connection_id)
250 	ZEND_ARG_INFO(0, data_type)
251 ZEND_END_ARG_INFO()
252 
253 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_primarykeys, 0, 0, 4)
254 	ZEND_ARG_INFO(0, connection_id)
255 	ZEND_ARG_INFO(0, qualifier)
256 	ZEND_ARG_INFO(0, owner)
257 	ZEND_ARG_INFO(0, table)
258 ZEND_END_ARG_INFO()
259 
260 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
261 #if !defined(HAVE_BIRDSTEP)
262 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedurecolumns, 0, 0, 1)
263 	ZEND_ARG_INFO(0, connection_id)
264 	ZEND_ARG_INFO(0, qualifier)
265 	ZEND_ARG_INFO(0, owner)
266 	ZEND_ARG_INFO(0, proc)
267 	ZEND_ARG_INFO(0, column)
268 ZEND_END_ARG_INFO()
269 #endif
270 
271 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedures, 0, 0, 1)
272 	ZEND_ARG_INFO(0, connection_id)
273 	ZEND_ARG_INFO(0, qualifier)
274 	ZEND_ARG_INFO(0, owner)
275 	ZEND_ARG_INFO(0, name)
276 ZEND_END_ARG_INFO()
277 
278 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7)
279 	ZEND_ARG_INFO(0, connection_id)
280 	ZEND_ARG_INFO(0, pk_qualifier)
281 	ZEND_ARG_INFO(0, pk_owner)
282 	ZEND_ARG_INFO(0, pk_table)
283 	ZEND_ARG_INFO(0, fk_qualifier)
284 	ZEND_ARG_INFO(0, fk_owner)
285 	ZEND_ARG_INFO(0, fk_table)
286 ZEND_END_ARG_INFO()
287 #endif
288 
289 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7)
290 	ZEND_ARG_INFO(0, connection_id)
291 	ZEND_ARG_INFO(0, type)
292 	ZEND_ARG_INFO(0, qualifier)
293 	ZEND_ARG_INFO(0, owner)
294 	ZEND_ARG_INFO(0, table)
295 	ZEND_ARG_INFO(0, scope)
296 	ZEND_ARG_INFO(0, nullable)
297 ZEND_END_ARG_INFO()
298 
299 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6)
300 	ZEND_ARG_INFO(0, connection_id)
301 	ZEND_ARG_INFO(0, qualifier)
302 	ZEND_ARG_INFO(0, owner)
303 	ZEND_ARG_INFO(0, name)
304 	ZEND_ARG_INFO(0, unique)
305 	ZEND_ARG_INFO(0, accuracy)
306 ZEND_END_ARG_INFO()
307 
308 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
309 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tableprivileges, 0, 0, 4)
310 	ZEND_ARG_INFO(0, connection_id)
311 	ZEND_ARG_INFO(0, qualifier)
312 	ZEND_ARG_INFO(0, owner)
313 	ZEND_ARG_INFO(0, name)
314 ZEND_END_ARG_INFO()
315 
316 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columnprivileges, 0, 0, 5)
317 	ZEND_ARG_INFO(0, connection_id)
318 	ZEND_ARG_INFO(0, catalog)
319 	ZEND_ARG_INFO(0, schema)
320 	ZEND_ARG_INFO(0, table)
321 	ZEND_ARG_INFO(0, column)
322 ZEND_END_ARG_INFO()
323 #endif
324 /* }}} */
325 
326 /* {{{ odbc_functions[]
327  */
328 const zend_function_entry odbc_functions[] = {
329 	PHP_FE(odbc_autocommit, arginfo_odbc_autocommit)
330 	PHP_FE(odbc_binmode, arginfo_odbc_binmode)
331 	PHP_FE(odbc_close, arginfo_odbc_close)
332 	PHP_FE(odbc_close_all, arginfo_odbc_close_all)
333 	PHP_FE(odbc_columns, arginfo_odbc_columns)
334 	PHP_FE(odbc_commit, arginfo_odbc_commit)
335 	PHP_FE(odbc_connect, arginfo_odbc_connect)
336 	PHP_FE(odbc_cursor, arginfo_odbc_cursor)
337 #ifdef HAVE_SQLDATASOURCES
338 	PHP_FE(odbc_data_source, arginfo_odbc_data_source)
339 #endif
340 	PHP_FE(odbc_execute, arginfo_odbc_execute)
341 	PHP_FE(odbc_error, arginfo_odbc_error)
342 	PHP_FE(odbc_errormsg, arginfo_odbc_errormsg)
343 	PHP_FE(odbc_exec, arginfo_odbc_exec)
344 #ifdef PHP_ODBC_HAVE_FETCH_HASH
345 	PHP_FE(odbc_fetch_array, arginfo_odbc_fetch_array)
346 	PHP_FE(odbc_fetch_object, arginfo_odbc_fetch_object)
347 #endif
348 	PHP_FE(odbc_fetch_row, arginfo_odbc_fetch_row)
349 	PHP_FE(odbc_fetch_into, arginfo_odbc_fetch_into)
350 	PHP_FE(odbc_field_len, arginfo_odbc_field_len)
351 	PHP_FE(odbc_field_scale, arginfo_odbc_field_scale)
352 	PHP_FE(odbc_field_name, arginfo_odbc_field_name)
353 	PHP_FE(odbc_field_type, arginfo_odbc_field_type)
354 	PHP_FE(odbc_field_num, arginfo_odbc_field_num)
355 	PHP_FE(odbc_free_result, arginfo_odbc_free_result)
356 	PHP_FE(odbc_gettypeinfo, arginfo_odbc_gettypeinfo)
357 	PHP_FE(odbc_longreadlen, arginfo_odbc_longreadlen)
358 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
359 	PHP_FE(odbc_next_result, arginfo_odbc_next_result)
360 #endif
361 	PHP_FE(odbc_num_fields, arginfo_odbc_num_fields)
362 	PHP_FE(odbc_num_rows, arginfo_odbc_num_rows)
363 	PHP_FE(odbc_pconnect, arginfo_odbc_pconnect)
364 	PHP_FE(odbc_prepare, arginfo_odbc_prepare)
365 	PHP_FE(odbc_result, arginfo_odbc_result)
366 	PHP_FE(odbc_result_all, arginfo_odbc_result_all)
367 	PHP_FE(odbc_rollback, arginfo_odbc_rollback)
368 	PHP_FE(odbc_setoption, arginfo_odbc_setoption)
369 	PHP_FE(odbc_specialcolumns, arginfo_odbc_specialcolumns)
370 	PHP_FE(odbc_statistics, arginfo_odbc_statistics)
371 	PHP_FE(odbc_tables, arginfo_odbc_tables)
372 	PHP_FE(odbc_primarykeys, arginfo_odbc_primarykeys)
373 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)    /* not supported now */
374 	PHP_FE(odbc_columnprivileges, arginfo_odbc_columnprivileges)
375 	PHP_FE(odbc_tableprivileges, arginfo_odbc_tableprivileges)
376 #endif
377 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) /* not supported */
378 	PHP_FE(odbc_foreignkeys, arginfo_odbc_foreignkeys)
379 	PHP_FE(odbc_procedures, arginfo_odbc_procedures)
380 #if !defined(HAVE_BIRDSTEP)
381 	PHP_FE(odbc_procedurecolumns, arginfo_odbc_procedurecolumns)
382 #endif
383 #endif
384 	PHP_FALIAS(odbc_do, odbc_exec, arginfo_odbc_exec)
385 	PHP_FALIAS(odbc_field_precision, odbc_field_len, arginfo_odbc_field_len)
386 	PHP_FE_END
387 };
388 /* }}} */
389 
390 ZEND_DECLARE_MODULE_GLOBALS(odbc)
391 static PHP_GINIT_FUNCTION(odbc);
392 
393 /* {{{ odbc_module_entry
394  */
395 zend_module_entry odbc_module_entry = {
396 	STANDARD_MODULE_HEADER,
397 	"odbc",
398 	odbc_functions,
399 	PHP_MINIT(odbc),
400 	PHP_MSHUTDOWN(odbc),
401 	PHP_RINIT(odbc),
402 	PHP_RSHUTDOWN(odbc),
403 	PHP_MINFO(odbc),
404 	"1.0",
405 	PHP_MODULE_GLOBALS(odbc),
406 	PHP_GINIT(odbc),
407 	NULL,
408 	NULL,
409 	STANDARD_MODULE_PROPERTIES_EX
410 };
411 /* }}} */
412 
413 #ifdef COMPILE_DL_ODBC
ZEND_GET_MODULE(odbc)414 ZEND_GET_MODULE(odbc)
415 #endif
416 
417 /* {{{ _free_odbc_result
418  */
419 static void _free_odbc_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
420 {
421 	odbc_result *res = (odbc_result *)rsrc->ptr;
422 	int i;
423 	RETCODE rc;
424 
425 	if (res) {
426 		if (res->values) {
427 			for(i = 0; i < res->numcols; i++) {
428 				if (res->values[i].value)
429 					efree(res->values[i].value);
430 			}
431 			efree(res->values);
432 			res->values = NULL;
433 		}
434 		if (res->stmt) {
435 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
436 			SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc,
437 						(SQLUSMALLINT) SQL_COMMIT);
438 #endif
439 			rc = SQLFreeStmt(res->stmt,SQL_DROP);
440 			/* We don't want the connection to be closed after the last statment has been closed
441 			 * Connections will be closed on shutdown
442 			 * zend_list_delete(res->conn_ptr->id);
443 			 */
444 		}
445 		efree(res);
446 	}
447 }
448 /* }}} */
449 
450 /* {{{ safe_odbc_disconnect
451  * disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher)
452  */
safe_odbc_disconnect(void * handle)453 static void safe_odbc_disconnect( void *handle )
454 {
455 	int ret;
456 
457 	ret = SQLDisconnect( handle );
458 	if ( ret == SQL_ERROR )
459 	{
460 		SQLTransact( NULL, handle, SQL_ROLLBACK );
461 		SQLDisconnect( handle );
462 	}
463 }
464 /* }}} */
465 
466 /* {{{ _close_odbc_conn
467  */
_close_odbc_conn(zend_rsrc_list_entry * rsrc TSRMLS_DC)468 static void _close_odbc_conn(zend_rsrc_list_entry *rsrc TSRMLS_DC)
469 {
470 	int i, nument, type;
471 	void *ptr;
472 	odbc_result *res;
473 
474 	odbc_connection *conn = (odbc_connection *)rsrc->ptr;
475 
476 	nument = zend_hash_next_free_element(&EG(regular_list));
477 	for(i = 1; i < nument; i++) {
478 		ptr = zend_list_find(i, &type);
479 		if (ptr && (type == le_result)) {
480 			res = (odbc_result *)ptr;
481 			if (res->conn_ptr == conn) {
482 				zend_list_delete(i);
483 			}
484 		}
485 	}
486 
487    	safe_odbc_disconnect(conn->hdbc);
488 	SQLFreeConnect(conn->hdbc);
489 	SQLFreeEnv(conn->henv);
490 	efree(conn);
491 	ODBCG(num_links)--;
492 }
493 /* }}} */
494 
495 /* {{{ void _close_odbc_pconn
496  */
_close_odbc_pconn(zend_rsrc_list_entry * rsrc TSRMLS_DC)497 static void _close_odbc_pconn(zend_rsrc_list_entry *rsrc TSRMLS_DC)
498 {
499 	int i, nument, type;
500 	void *ptr;
501 	odbc_result *res;
502 	odbc_connection *conn = (odbc_connection *)rsrc->ptr;
503 
504 	nument = zend_hash_next_free_element(&EG(persistent_list));
505 	for(i = 1; i < nument; i++) {
506 		ptr = zend_list_find(i, &type);
507 		if (ptr && (type == le_result)) {
508 			res = (odbc_result *)ptr;
509 			if (res->conn_ptr == conn) {
510 				zend_list_delete(i);
511 			}
512 		}
513 	}
514 
515 	safe_odbc_disconnect(conn->hdbc);
516 	SQLFreeConnect(conn->hdbc);
517 	SQLFreeEnv(conn->henv);
518 	free(conn);
519 
520 	ODBCG(num_links)--;
521 	ODBCG(num_persistent)--;
522 }
523 /* }}} */
524 
525 /* {{{ PHP_INI_DISP(display_link_nums)
526  */
PHP_INI_DISP(display_link_nums)527 static PHP_INI_DISP(display_link_nums)
528 {
529 	char *value;
530 	TSRMLS_FETCH();
531 
532 	if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
533 		value = ini_entry->orig_value;
534 	} else if (ini_entry->value) {
535 		value = ini_entry->value;
536 	} else {
537 		value = NULL;
538 	}
539 
540 	if (value) {
541 		if (atoi(value) == -1) {
542 			PUTS("Unlimited");
543 		} else {
544 			php_printf("%s", value);
545 		}
546 	}
547 }
548 /* }}} */
549 
550 /* {{{ PHP_INI_DISP(display_defPW)
551  */
PHP_INI_DISP(display_defPW)552 static PHP_INI_DISP(display_defPW)
553 {
554 	char *value;
555 	TSRMLS_FETCH();
556 
557 	if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
558 		value = ini_entry->orig_value;
559 	} else if (ini_entry->value) {
560 		value = ini_entry->value;
561 	} else {
562 		value = NULL;
563 	}
564 
565 	if (value) {
566 #if PHP_DEBUG
567 		php_printf("%s", value);
568 #else
569 		PUTS("********");
570 #endif
571 	} else {
572 		if (PG(html_errors)) {
573 			PUTS("<i>no value</i>");
574 		} else {
575 			PUTS("no value");
576 		}
577 	}
578 }
579 /* }}} */
580 
581 /* {{{ PHP_INI_DISP(display_binmode)
582  */
PHP_INI_DISP(display_binmode)583 static PHP_INI_DISP(display_binmode)
584 {
585 	char *value;
586 	TSRMLS_FETCH();
587 
588 	if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
589 		value = ini_entry->orig_value;
590 	} else if (ini_entry->value) {
591 		value = ini_entry->value;
592 	} else {
593 		value = NULL;
594 	}
595 
596 	if (value) {
597 		switch(atoi(value)) {
598 			case 0:
599 				PUTS("passthru");
600 				break;
601 			case 1:
602 				PUTS("return as is");
603 				break;
604 			case 2:
605 				PUTS("return as char");
606 				break;
607 		}
608 	}
609 }
610 /* }}} */
611 
612 /* {{{ PHP_INI_DISP(display_lrl)
613  */
PHP_INI_DISP(display_lrl)614 static PHP_INI_DISP(display_lrl)
615 {
616 	char *value;
617 	TSRMLS_FETCH();
618 
619 	if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
620 		value = ini_entry->orig_value;
621 	} else if (ini_entry->value) {
622 		value = ini_entry->value;
623 	} else {
624 		value = NULL;
625 	}
626 
627 	if (value) {
628 		if (atoi(value) <= 0) {
629 			PUTS("Passthru");
630 		} else {
631 			php_printf("return up to %s bytes", value);
632 		}
633 	}
634 }
635 /* }}} */
636 
637 
638 /* {{{ PHP_INI_DISP(display_cursortype)
639  */
PHP_INI_DISP(display_cursortype)640 static PHP_INI_DISP(display_cursortype)
641 {
642 	char *value;
643 	TSRMLS_FETCH();
644 
645 	if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
646 		value = ini_entry->orig_value;
647 	} else if (ini_entry->value) {
648 		value = ini_entry->value;
649 	} else {
650 		value = NULL;
651 	}
652 
653 	if (value) {
654 		switch (atoi (value))
655 		  {
656 		    case SQL_CURSOR_FORWARD_ONLY:
657 				PUTS ("Forward Only cursor");
658 				break;
659 
660 			case SQL_CURSOR_STATIC:
661 			    PUTS ("Static cursor");
662 				break;
663 
664 			case SQL_CURSOR_KEYSET_DRIVEN:
665 				PUTS ("Keyset driven cursor");
666 				break;
667 
668 			case SQL_CURSOR_DYNAMIC:
669 				PUTS ("Dynamic cursor");
670 				break;
671 
672 			default:
673 				php_printf("Unknown cursor model %s", value);
674 				break;
675 		  }
676 	}
677 }
678 
679 /* }}} */
680 
681 /* {{{ PHP_INI_BEGIN
682  */
683 PHP_INI_BEGIN()
684 	STD_PHP_INI_BOOLEAN("odbc.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong,
685 			allow_persistent, zend_odbc_globals, odbc_globals)
686 	STD_PHP_INI_ENTRY_EX("odbc.max_persistent",  "-1", PHP_INI_SYSTEM, OnUpdateLong,
687 			max_persistent, zend_odbc_globals, odbc_globals, display_link_nums)
688 	STD_PHP_INI_ENTRY_EX("odbc.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong,
689 			max_links, zend_odbc_globals, odbc_globals, display_link_nums)
690 	STD_PHP_INI_ENTRY("odbc.default_db", NULL, PHP_INI_ALL, OnUpdateString,
691 			defDB, zend_odbc_globals, odbc_globals)
692 	STD_PHP_INI_ENTRY("odbc.default_user", NULL, PHP_INI_ALL, OnUpdateString,
693 			defUser, zend_odbc_globals, odbc_globals)
694 	STD_PHP_INI_ENTRY_EX("odbc.default_pw", NULL, PHP_INI_ALL, OnUpdateString,
695 			defPW, zend_odbc_globals, odbc_globals, display_defPW)
696 	STD_PHP_INI_ENTRY_EX("odbc.defaultlrl", "4096", PHP_INI_ALL, OnUpdateLong,
697 			defaultlrl, zend_odbc_globals, odbc_globals, display_lrl)
698 	STD_PHP_INI_ENTRY_EX("odbc.defaultbinmode", "1", PHP_INI_ALL, OnUpdateLong,
699 			defaultbinmode, zend_odbc_globals, odbc_globals, display_binmode)
700 	STD_PHP_INI_BOOLEAN("odbc.check_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong,
701 			check_persistent, zend_odbc_globals, odbc_globals)
702 	STD_PHP_INI_ENTRY_EX("odbc.default_cursortype", "3", PHP_INI_ALL, OnUpdateLong,
703 			default_cursortype, zend_odbc_globals, odbc_globals, display_cursortype)
PHP_INI_END()704 PHP_INI_END()
705 /* }}} */
706 
707 static PHP_GINIT_FUNCTION(odbc)
708 {
709 	odbc_globals->num_persistent = 0;
710 }
711 
712 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(odbc)713 PHP_MINIT_FUNCTION(odbc)
714 {
715 #ifdef SQLANY_BUG
716 	ODBC_SQL_CONN_T foobar;
717 	RETCODE rc;
718 #endif
719 
720 	REGISTER_INI_ENTRIES();
721 	le_result = zend_register_list_destructors_ex(_free_odbc_result, NULL, "odbc result", module_number);
722 	le_conn = zend_register_list_destructors_ex(_close_odbc_conn, NULL, "odbc link", module_number);
723 	le_pconn = zend_register_list_destructors_ex(NULL, _close_odbc_pconn, "odbc link persistent", module_number);
724 	Z_TYPE(odbc_module_entry) = type;
725 
726 	REGISTER_STRING_CONSTANT("ODBC_TYPE", PHP_ODBC_TYPE, CONST_CS | CONST_PERSISTENT);
727 	REGISTER_LONG_CONSTANT("ODBC_BINMODE_PASSTHRU", 0, CONST_CS | CONST_PERSISTENT);
728 	REGISTER_LONG_CONSTANT("ODBC_BINMODE_RETURN", 1, CONST_CS | CONST_PERSISTENT);
729 	REGISTER_LONG_CONSTANT("ODBC_BINMODE_CONVERT", 2, CONST_CS | CONST_PERSISTENT);
730 	/* Define Constants for options
731 	   these Constants are defined in <sqlext.h>
732 	*/
733 	REGISTER_LONG_CONSTANT("SQL_ODBC_CURSORS", SQL_ODBC_CURSORS, CONST_PERSISTENT | CONST_CS);
734 	REGISTER_LONG_CONSTANT("SQL_CUR_USE_DRIVER", SQL_CUR_USE_DRIVER, CONST_PERSISTENT | CONST_CS);
735 	REGISTER_LONG_CONSTANT("SQL_CUR_USE_IF_NEEDED", SQL_CUR_USE_IF_NEEDED, CONST_PERSISTENT | CONST_CS);
736 	REGISTER_LONG_CONSTANT("SQL_CUR_USE_ODBC", SQL_CUR_USE_ODBC, CONST_PERSISTENT | CONST_CS);
737 
738 
739 	REGISTER_LONG_CONSTANT("SQL_CONCURRENCY", SQL_CONCURRENCY, CONST_PERSISTENT | CONST_CS);
740 	REGISTER_LONG_CONSTANT("SQL_CONCUR_READ_ONLY", SQL_CONCUR_READ_ONLY, CONST_PERSISTENT | CONST_CS);
741 	REGISTER_LONG_CONSTANT("SQL_CONCUR_LOCK", SQL_CONCUR_LOCK, CONST_PERSISTENT | CONST_CS);
742 	REGISTER_LONG_CONSTANT("SQL_CONCUR_ROWVER", SQL_CONCUR_ROWVER, CONST_PERSISTENT | CONST_CS);
743 	REGISTER_LONG_CONSTANT("SQL_CONCUR_VALUES", SQL_CONCUR_VALUES, CONST_PERSISTENT | CONST_CS);
744 
745 	REGISTER_LONG_CONSTANT("SQL_CURSOR_TYPE", SQL_CURSOR_TYPE, CONST_PERSISTENT | CONST_CS);
746 	REGISTER_LONG_CONSTANT("SQL_CURSOR_FORWARD_ONLY", SQL_CURSOR_FORWARD_ONLY, CONST_PERSISTENT | CONST_CS);
747 	REGISTER_LONG_CONSTANT("SQL_CURSOR_KEYSET_DRIVEN", SQL_CURSOR_KEYSET_DRIVEN, CONST_PERSISTENT | CONST_CS);
748 	REGISTER_LONG_CONSTANT("SQL_CURSOR_DYNAMIC", SQL_CURSOR_DYNAMIC, CONST_PERSISTENT | CONST_CS);
749 	REGISTER_LONG_CONSTANT("SQL_CURSOR_STATIC", SQL_CURSOR_STATIC, CONST_PERSISTENT | CONST_CS);
750 
751 	REGISTER_LONG_CONSTANT("SQL_KEYSET_SIZE", SQL_KEYSET_SIZE, CONST_PERSISTENT | CONST_CS);
752 
753 	/* these are for the Data Source type */
754 	REGISTER_LONG_CONSTANT("SQL_FETCH_FIRST", SQL_FETCH_FIRST, CONST_PERSISTENT | CONST_CS);
755 	REGISTER_LONG_CONSTANT("SQL_FETCH_NEXT", SQL_FETCH_NEXT, CONST_PERSISTENT | CONST_CS);
756 
757 	/*
758 	 * register the standard data types
759 	 */
760 	REGISTER_LONG_CONSTANT("SQL_CHAR", SQL_CHAR, CONST_PERSISTENT | CONST_CS);
761 	REGISTER_LONG_CONSTANT("SQL_VARCHAR", SQL_VARCHAR, CONST_PERSISTENT | CONST_CS);
762 	REGISTER_LONG_CONSTANT("SQL_LONGVARCHAR", SQL_LONGVARCHAR, CONST_PERSISTENT | CONST_CS);
763 	REGISTER_LONG_CONSTANT("SQL_DECIMAL", SQL_DECIMAL, CONST_PERSISTENT | CONST_CS);
764 	REGISTER_LONG_CONSTANT("SQL_NUMERIC", SQL_NUMERIC, CONST_PERSISTENT | CONST_CS);
765 	REGISTER_LONG_CONSTANT("SQL_BIT", SQL_BIT, CONST_PERSISTENT | CONST_CS);
766 	REGISTER_LONG_CONSTANT("SQL_TINYINT", SQL_TINYINT, CONST_PERSISTENT | CONST_CS);
767 	REGISTER_LONG_CONSTANT("SQL_SMALLINT", SQL_SMALLINT, CONST_PERSISTENT | CONST_CS);
768 	REGISTER_LONG_CONSTANT("SQL_INTEGER", SQL_INTEGER, CONST_PERSISTENT | CONST_CS);
769 	REGISTER_LONG_CONSTANT("SQL_BIGINT", SQL_BIGINT, CONST_PERSISTENT | CONST_CS);
770 	REGISTER_LONG_CONSTANT("SQL_REAL", SQL_REAL, CONST_PERSISTENT | CONST_CS);
771 	REGISTER_LONG_CONSTANT("SQL_FLOAT", SQL_FLOAT, CONST_PERSISTENT | CONST_CS);
772 	REGISTER_LONG_CONSTANT("SQL_DOUBLE", SQL_DOUBLE, CONST_PERSISTENT | CONST_CS);
773 	REGISTER_LONG_CONSTANT("SQL_BINARY", SQL_BINARY, CONST_PERSISTENT | CONST_CS);
774 	REGISTER_LONG_CONSTANT("SQL_VARBINARY", SQL_VARBINARY, CONST_PERSISTENT | CONST_CS);
775 	REGISTER_LONG_CONSTANT("SQL_LONGVARBINARY", SQL_LONGVARBINARY, CONST_PERSISTENT | CONST_CS);
776 	REGISTER_LONG_CONSTANT("SQL_DATE", SQL_DATE, CONST_PERSISTENT | CONST_CS);
777 	REGISTER_LONG_CONSTANT("SQL_TIME", SQL_TIME, CONST_PERSISTENT | CONST_CS);
778 	REGISTER_LONG_CONSTANT("SQL_TIMESTAMP", SQL_TIMESTAMP, CONST_PERSISTENT | CONST_CS);
779 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
780 	REGISTER_LONG_CONSTANT("SQL_TYPE_DATE", SQL_TYPE_DATE, CONST_PERSISTENT | CONST_CS);
781 	REGISTER_LONG_CONSTANT("SQL_TYPE_TIME", SQL_TYPE_TIME, CONST_PERSISTENT | CONST_CS);
782 	REGISTER_LONG_CONSTANT("SQL_TYPE_TIMESTAMP", SQL_TYPE_TIMESTAMP, CONST_PERSISTENT | CONST_CS);
783 
784 	/*
785 	 * SQLSpecialColumns values
786 	 */
787 	REGISTER_LONG_CONSTANT("SQL_BEST_ROWID", SQL_BEST_ROWID, CONST_PERSISTENT | CONST_CS);
788 	REGISTER_LONG_CONSTANT("SQL_ROWVER", SQL_ROWVER, CONST_PERSISTENT | CONST_CS);
789 	REGISTER_LONG_CONSTANT("SQL_SCOPE_CURROW", SQL_SCOPE_CURROW, CONST_PERSISTENT | CONST_CS);
790 	REGISTER_LONG_CONSTANT("SQL_SCOPE_TRANSACTION", SQL_SCOPE_TRANSACTION, CONST_PERSISTENT | CONST_CS);
791 	REGISTER_LONG_CONSTANT("SQL_SCOPE_SESSION", SQL_SCOPE_SESSION, CONST_PERSISTENT | CONST_CS);
792 	REGISTER_LONG_CONSTANT("SQL_NO_NULLS", SQL_NO_NULLS, CONST_PERSISTENT | CONST_CS);
793 	REGISTER_LONG_CONSTANT("SQL_NULLABLE", SQL_NULLABLE, CONST_PERSISTENT | CONST_CS);
794 
795 	/*
796 	 * SQLStatistics values
797 	 */
798 	REGISTER_LONG_CONSTANT("SQL_INDEX_UNIQUE", SQL_INDEX_UNIQUE, CONST_PERSISTENT | CONST_CS);
799 	REGISTER_LONG_CONSTANT("SQL_INDEX_ALL", SQL_INDEX_ALL, CONST_PERSISTENT | CONST_CS);
800 	REGISTER_LONG_CONSTANT("SQL_ENSURE", SQL_ENSURE, CONST_PERSISTENT | CONST_CS);
801 	REGISTER_LONG_CONSTANT("SQL_QUICK", SQL_QUICK, CONST_PERSISTENT | CONST_CS);
802 #endif
803 
804 #if defined(HAVE_IBMDB2) && defined(_AIX)
805 	/* atexit() handler in the DB2/AIX library segfaults in PHP CLI */
806 	/* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */
807 	putenv("DB2NOEXITLIST=TRUE");
808 #endif
809 
810 	return SUCCESS;
811 }
812 /* }}} */
813 
814 /* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(odbc)815 PHP_RINIT_FUNCTION(odbc)
816 {
817 	ODBCG(defConn) = -1;
818 	ODBCG(num_links) = ODBCG(num_persistent);
819 	memset(ODBCG(laststate), '\0', 6);
820 	memset(ODBCG(lasterrormsg), '\0', SQL_MAX_MESSAGE_LENGTH);
821 	return SUCCESS;
822 }
823 /* }}} */
824 
825 /* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(odbc)826 PHP_RSHUTDOWN_FUNCTION(odbc)
827 {
828 	return SUCCESS;
829 }
830 /* }}} */
831 
832 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(odbc)833 PHP_MSHUTDOWN_FUNCTION(odbc)
834 {
835 	UNREGISTER_INI_ENTRIES();
836 	return SUCCESS;
837 }
838 /* }}} */
839 
840 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(odbc)841 PHP_MINFO_FUNCTION(odbc)
842 {
843 	char buf[32];
844 
845 	php_info_print_table_start();
846 	php_info_print_table_header(2, "ODBC Support", "enabled");
847 	snprintf(buf, sizeof(buf), "%ld", ODBCG(num_persistent));
848 	php_info_print_table_row(2, "Active Persistent Links", buf);
849 	snprintf(buf, sizeof(buf), "%ld", ODBCG(num_links));
850 	php_info_print_table_row(2, "Active Links", buf);
851 	php_info_print_table_row(2, "ODBC library", PHP_ODBC_TYPE);
852 #ifndef PHP_WIN32
853 	php_info_print_table_row(2, "ODBC_INCLUDE", PHP_ODBC_INCLUDE);
854 	php_info_print_table_row(2, "ODBC_LFLAGS", PHP_ODBC_LFLAGS);
855 	php_info_print_table_row(2, "ODBC_LIBS", PHP_ODBC_LIBS);
856 #endif
857 	php_info_print_table_end();
858 
859 	DISPLAY_INI_ENTRIES();
860 
861 }
862 /* }}} */
863 
864 /* {{{ odbc_sql_error */
odbc_sql_error(ODBC_SQL_ERROR_PARAMS)865 void odbc_sql_error(ODBC_SQL_ERROR_PARAMS)
866 {
867 	char   	    state[6];
868 	SQLINTEGER	error;        /* Not used */
869 	char   	    errormsg[SQL_MAX_MESSAGE_LENGTH];
870 	SQLSMALLINT	errormsgsize; /* Not used */
871 	RETCODE rc;
872 	ODBC_SQL_ENV_T henv;
873 	ODBC_SQL_CONN_T conn;
874 	TSRMLS_FETCH();
875 
876 	if (conn_resource) {
877 		henv = conn_resource->henv;
878 		conn = conn_resource->hdbc;
879 	} else {
880 		henv = SQL_NULL_HENV;
881 		conn = SQL_NULL_HDBC;
882 	}
883 
884 	/* This leads to an endless loop in many drivers!
885 	 *
886 	   while(henv != SQL_NULL_HENV){
887 		do {
888 	 */
889 	rc = SQLError(henv, conn, stmt, state, &error, errormsg, sizeof(errormsg)-1, &errormsgsize);
890 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
891 		snprintf(state, sizeof(state), "HY000");
892 		snprintf(errormsg, sizeof(errormsg), "Failed to fetch error message");
893 	}
894 	if (conn_resource) {
895 		memcpy(conn_resource->laststate, state, sizeof(state));
896 		memcpy(conn_resource->lasterrormsg, errormsg, sizeof(errormsg));
897 	}
898 	memcpy(ODBCG(laststate), state, sizeof(state));
899 	memcpy(ODBCG(lasterrormsg), errormsg, sizeof(errormsg));
900 	if (func) {
901 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s in %s", errormsg, state, func);
902 	} else {
903 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
904 	}
905 	/*
906 		} while (SQL_SUCCEEDED(rc));
907 	}
908 	*/
909 }
910 /* }}} */
911 
912 /* {{{ php_odbc_fetch_attribs */
php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS,int mode)913 void php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS, int mode)
914 {
915 	odbc_result *result;
916 	zval *pv_res;
917 	long flag;
918 
919 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &flag) == FAILURE) {
920 		return;
921 	}
922 
923 	if (Z_LVAL_P(pv_res)) {
924 		ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
925         if (mode) {
926             result->longreadlen = flag;
927         } else {
928             result->binmode = flag;
929 		}
930 	} else {
931         if (mode) {
932             ODBCG(defaultlrl) = flag;
933         } else {
934             ODBCG(defaultbinmode) = flag;
935 		}
936 	}
937 	RETURN_TRUE;
938 }
939 /* }}} */
940 
941 /* {{{ odbc_bindcols */
odbc_bindcols(odbc_result * result TSRMLS_DC)942 int odbc_bindcols(odbc_result *result TSRMLS_DC)
943 {
944 	RETCODE rc;
945 	int i;
946 	SQLSMALLINT colnamelen; /* Not used */
947 	SQLLEN      displaysize;
948 
949 	result->values = (odbc_result_value *) safe_emalloc(sizeof(odbc_result_value), result->numcols, 0);
950 
951 	result->longreadlen = ODBCG(defaultlrl);
952 	result->binmode = ODBCG(defaultbinmode);
953 
954 	for(i = 0; i < result->numcols; i++) {
955 		rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_NAME,
956 				result->values[i].name, sizeof(result->values[i].name), &colnamelen, 0);
957 		rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_TYPE,
958 				NULL, 0, NULL, &result->values[i].coltype);
959 
960 		/* Don't bind LONG / BINARY columns, so that fetch behaviour can
961 		 * be controlled by odbc_binmode() / odbc_longreadlen()
962 		 */
963 
964 		switch(result->values[i].coltype) {
965 			case SQL_BINARY:
966 			case SQL_VARBINARY:
967 			case SQL_LONGVARBINARY:
968 			case SQL_LONGVARCHAR:
969 				result->values[i].value = NULL;
970 				break;
971 
972 #ifdef HAVE_ADABAS
973 			case SQL_TIMESTAMP:
974 				result->values[i].value = (char *)emalloc(27);
975 				SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
976 							27, &result->values[i].vallen);
977 				break;
978 #endif /* HAVE_ADABAS */
979 			default:
980 				rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE,
981 									NULL, 0, NULL, &displaysize);
982 				displaysize = displaysize <= result->longreadlen ? displaysize :
983 								result->longreadlen;
984 				/* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */
985 				if (result->values[i].coltype == SQL_TIMESTAMP) {
986 					displaysize += 3;
987 				}
988 				result->values[i].value = (char *)emalloc(displaysize + 1);
989 				rc = SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
990 							displaysize + 1, &result->values[i].vallen);
991 				break;
992 		}
993 	}
994 	return 1;
995 }
996 /* }}} */
997 
998 /* {{{ odbc_transact */
odbc_transact(INTERNAL_FUNCTION_PARAMETERS,int type)999 void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type)
1000 {
1001 	odbc_connection *conn;
1002 	RETCODE rc;
1003 	zval *pv_conn;
1004 
1005 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
1006 		return;
1007 	}
1008 
1009 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1010 
1011 	rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK));
1012 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1013 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTransact");
1014 		RETURN_FALSE;
1015 	}
1016 
1017 	RETURN_TRUE;
1018 }
1019 /* }}} */
1020 
1021 /* {{{ _close_pconn_with_id */
_close_pconn_with_id(zend_rsrc_list_entry * le,int * id TSRMLS_DC)1022 static int _close_pconn_with_id(zend_rsrc_list_entry *le, int *id TSRMLS_DC)
1023 {
1024 	if(Z_TYPE_P(le) == le_pconn && (((odbc_connection *)(le->ptr))->id == *id)){
1025 		return 1;
1026 	}else{
1027 		return 0;
1028 	}
1029 }
1030 /* }}} */
1031 
1032 /* {{{ odbc_column_lengths */
odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS,int type)1033 void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
1034 {
1035 	odbc_result *result;
1036 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
1037 	/* this seems to be necessary for Solid2.3 ( tested by
1038 	 * tammy@synchronis.com) and Solid 3.0 (tested by eric@terra.telemediair.nl)
1039 	 * Solid does not seem to declare a SQLINTEGER, but it does declare a
1040 	 * SQL_INTEGER which does not work (despite being the same type as a SDWORD.
1041 	 * Solid 3.5 does not have this issue.
1042 	 */
1043 	SDWORD len;
1044 #else
1045 	SQLLEN len;
1046 #endif
1047 	zval *pv_res;
1048 	long pv_num;
1049 
1050 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
1051 		return;
1052 	}
1053 
1054 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1055 
1056 	if (result->numcols == 0) {
1057 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1058 		RETURN_FALSE;
1059 	}
1060 
1061 	if (pv_num > result->numcols) {
1062 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
1063 		RETURN_FALSE;
1064 	}
1065 
1066 	if (pv_num < 1) {
1067 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
1068 		RETURN_FALSE;
1069 	}
1070 
1071 	SQLColAttributes(result->stmt, (SQLUSMALLINT)pv_num, (SQLUSMALLINT) (type?SQL_COLUMN_SCALE:SQL_COLUMN_PRECISION), NULL, 0, NULL, &len);
1072 
1073 	RETURN_LONG(len);
1074 }
1075 /* }}} */
1076 
1077 /* Main User Functions */
1078 
1079 /* {{{ proto void odbc_close_all(void)
1080    Close all ODBC connections */
PHP_FUNCTION(odbc_close_all)1081 PHP_FUNCTION(odbc_close_all)
1082 {
1083 	void *ptr;
1084 	int type;
1085 	int i;
1086 	int nument;
1087 
1088 	if (zend_parse_parameters_none() == FAILURE) {
1089 		return;
1090 	}
1091 
1092 	nument = zend_hash_next_free_element(&EG(regular_list));
1093 
1094 	/* Loop through list and close all statements */
1095 	for(i = 1; i < nument; i++) {
1096 		ptr = zend_list_find(i, &type);
1097 		if (ptr && (type == le_result)){
1098 			zend_list_delete(i);
1099 		}
1100 	}
1101 
1102 	/* Second loop through list, now close all connections */
1103 	nument = zend_hash_next_free_element(&EG(regular_list));
1104 
1105 	for(i = 1; i < nument; i++) {
1106 		ptr = zend_list_find(i, &type);
1107 		if (ptr){
1108 			if(type == le_conn){
1109 				zend_list_delete(i);
1110 			}else if(type == le_pconn){
1111 				zend_list_delete(i);
1112 				/* Delete the persistent connection */
1113 				zend_hash_apply_with_argument(&EG(persistent_list),
1114 					(apply_func_arg_t) _close_pconn_with_id, (void *) &i TSRMLS_CC);
1115 			}
1116 		}
1117 	}
1118 }
1119 /* }}} */
1120 
1121 /* {{{ proto bool odbc_binmode(int result_id, int mode)
1122    Handle binary column data */
PHP_FUNCTION(odbc_binmode)1123 PHP_FUNCTION(odbc_binmode)
1124 {
1125 	php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1126 }
1127 /* }}} */
1128 
1129 /* {{{ proto bool odbc_longreadlen(int result_id, int length)
1130    Handle LONG columns */
PHP_FUNCTION(odbc_longreadlen)1131 PHP_FUNCTION(odbc_longreadlen)
1132 {
1133 	php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1134 }
1135 /* }}} */
1136 
1137 /* {{{ proto resource odbc_prepare(resource connection_id, string query)
1138    Prepares a statement for execution */
PHP_FUNCTION(odbc_prepare)1139 PHP_FUNCTION(odbc_prepare)
1140 {
1141 	zval *pv_conn;
1142 	char *query;
1143 	int query_len;
1144 	odbc_result *result = NULL;
1145 	odbc_connection *conn;
1146 	RETCODE rc;
1147 #ifdef HAVE_SQL_EXTENDED_FETCH
1148 	SQLUINTEGER      scrollopts;
1149 #endif
1150 
1151 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_conn, &query, &query_len) == FAILURE) {
1152 		return;
1153 	}
1154 
1155 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1156 
1157 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
1158 
1159 	result->numparams = 0;
1160 
1161 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
1162 	if (rc == SQL_INVALID_HANDLE) {
1163 		efree(result);
1164 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
1165 		RETURN_FALSE;
1166 	}
1167 
1168 	if (rc == SQL_ERROR) {
1169 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
1170 		efree(result);
1171 		RETURN_FALSE;
1172 	}
1173 
1174 #ifdef HAVE_SQL_EXTENDED_FETCH
1175 	/* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
1176 	   whether Driver supports ExtendedFetch */
1177 	rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
1178 	if (rc == SQL_SUCCESS) {
1179 		if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
1180 			/* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
1181 			   type if not possible.
1182 			*/
1183 			SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
1184 		}
1185 	} else {
1186 		result->fetch_abs = 0;
1187 	}
1188 #endif
1189 
1190 	rc = SQLPrepare(result->stmt, query, SQL_NTS);
1191 	switch (rc) {
1192 		case SQL_SUCCESS:
1193 			break;
1194 		case SQL_SUCCESS_WITH_INFO:
1195 			odbc_sql_error(conn, result->stmt, "SQLPrepare");
1196 			break;
1197 		default:
1198 			odbc_sql_error(conn, result->stmt, "SQLPrepare");
1199 			RETURN_FALSE;
1200 	}
1201 
1202 	SQLNumParams(result->stmt, &(result->numparams));
1203 	SQLNumResultCols(result->stmt, &(result->numcols));
1204 
1205 	if (result->numcols > 0) {
1206 		if (!odbc_bindcols(result TSRMLS_CC)) {
1207 			efree(result);
1208 			RETURN_FALSE;
1209 		}
1210 	} else {
1211 		result->values = NULL;
1212 	}
1213 	zend_list_addref(conn->id);
1214 	result->conn_ptr = conn;
1215 	result->fetched = 0;
1216 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1217 }
1218 /* }}} */
1219 
1220 /*
1221  * Execute prepared SQL statement. Supports only input parameters.
1222  */
1223 
1224 /* {{{ proto bool odbc_execute(resource result_id [, array parameters_array])
1225    Execute a prepared statement */
PHP_FUNCTION(odbc_execute)1226 PHP_FUNCTION(odbc_execute)
1227 {
1228 	zval *pv_res, *pv_param_arr, **tmp;
1229 	typedef struct params_t {
1230 		SQLLEN vallen;
1231 		int fp;
1232 	} params_t;
1233 	params_t *params = NULL;
1234 	char *filename;
1235 	unsigned char otype;
1236    	SQLSMALLINT sqltype, ctype, scale;
1237 	SQLSMALLINT nullable;
1238 	SQLULEN precision;
1239    	odbc_result *result;
1240 	int numArgs, i, ne;
1241 	RETCODE rc;
1242 
1243 	numArgs = ZEND_NUM_ARGS();
1244 
1245 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|a", &pv_res, &pv_param_arr) == FAILURE) {
1246 		return;
1247 	}
1248 
1249 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1250 
1251 	/* XXX check for already bound parameters*/
1252 	if (result->numparams > 0 && numArgs == 1) {
1253 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No parameters to SQL statement given");
1254 		RETURN_FALSE;
1255 	}
1256 
1257 	if (result->numparams > 0) {
1258 		if ((ne = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr))) < result->numparams) {
1259 			php_error_docref(NULL TSRMLS_CC, E_WARNING,"Not enough parameters (%d should be %d) given", ne, result->numparams);
1260 			RETURN_FALSE;
1261 		}
1262 
1263 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
1264 		params = (params_t *)safe_emalloc(sizeof(params_t), result->numparams, 0);
1265 		for(i = 0; i < result->numparams; i++) {
1266 			params[i].fp = -1;
1267 		}
1268 
1269 		for(i = 1; i <= result->numparams; i++) {
1270 			if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
1271 				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
1272 				SQLFreeStmt(result->stmt,SQL_RESET_PARAMS);
1273 				for (i = 0; i < result->numparams; i++) {
1274 					if (params[i].fp != -1) {
1275 						close(params[i].fp);
1276 					}
1277 				}
1278 				efree(params);
1279 				RETURN_FALSE;
1280 			}
1281 
1282 			otype = (*tmp)->type;
1283 			convert_to_string_ex(tmp);
1284 			if (Z_TYPE_PP(tmp) != IS_STRING) {
1285 				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
1286 				SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1287 				for (i = 0; i < result->numparams; i++) {
1288 					if (params[i].fp != -1) {
1289 						close(params[i].fp);
1290 					}
1291 				}
1292 				efree(params);
1293 				RETURN_FALSE;
1294 			}
1295 
1296 			rc = SQLDescribeParam(result->stmt, (SQLUSMALLINT)i, &sqltype, &precision, &scale, &nullable);
1297 			params[i-1].vallen = Z_STRLEN_PP(tmp);
1298 			params[i-1].fp = -1;
1299 			if (rc == SQL_ERROR) {
1300 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter");
1301 				SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1302 				for (i = 0; i < result->numparams; i++) {
1303 					if (params[i].fp != -1) {
1304 						close(params[i].fp);
1305 					}
1306 				}
1307 				efree(params);
1308 				RETURN_FALSE;
1309 			}
1310 
1311 			if (IS_SQL_BINARY(sqltype)) {
1312 				ctype = SQL_C_BINARY;
1313 			} else {
1314 				ctype = SQL_C_CHAR;
1315 			}
1316 
1317 			if (Z_STRLEN_PP(tmp) > 2 &&
1318 				Z_STRVAL_PP(tmp)[0] == '\'' &&
1319 				Z_STRVAL_PP(tmp)[Z_STRLEN_PP(tmp) - 1] == '\'') {
1320 				if (strlen(Z_STRVAL_PP(tmp)) != Z_STRLEN_PP(tmp)) {
1321 					RETURN_FALSE;
1322 				}
1323 
1324 				filename = estrndup(&Z_STRVAL_PP(tmp)[1], Z_STRLEN_PP(tmp) - 2);
1325 
1326 				/* Check for safe mode. */
1327 				if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
1328 					efree(filename);
1329 					efree(params);
1330 					RETURN_FALSE;
1331 				}
1332 
1333 				/* Check the basedir */
1334 				if (php_check_open_basedir(filename TSRMLS_CC)) {
1335 					efree(filename);
1336 					SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1337 					for (i = 0; i < result->numparams; i++) {
1338 						if (params[i].fp != -1) {
1339 							close(params[i].fp);
1340 						}
1341 					}
1342 					efree(params);
1343 					RETURN_FALSE;
1344 				}
1345 
1346 				if ((params[i-1].fp = open(filename,O_RDONLY)) == -1) {
1347 					php_error_docref(NULL TSRMLS_CC, E_WARNING,"Can't open file %s", filename);
1348 					SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1349 					for (i = 0; i < result->numparams; i++) {
1350 						if (params[i].fp != -1) {
1351 							close(params[i].fp);
1352 						}
1353 					}
1354 					efree(params);
1355 					efree(filename);
1356 					RETURN_FALSE;
1357 				}
1358 
1359 				efree(filename);
1360 
1361 				params[i-1].vallen = SQL_LEN_DATA_AT_EXEC(0);
1362 
1363 				rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
1364 									  ctype, sqltype, precision, scale,
1365 									  (void *)params[i-1].fp, 0,
1366 									  &params[i-1].vallen);
1367 			} else {
1368 #ifdef HAVE_DBMAKER
1369 				precision = params[i-1].vallen;
1370 #endif
1371 				if (otype == IS_NULL) {
1372 					params[i-1].vallen = SQL_NULL_DATA;
1373 				}
1374 
1375 				rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
1376 									  ctype, sqltype, precision, scale,
1377 									  Z_STRVAL_PP(tmp), 0,
1378 									  &params[i-1].vallen);
1379 			}
1380 			if (rc == SQL_ERROR) {
1381 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLBindParameter");
1382 				SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1383 				for (i = 0; i < result->numparams; i++) {
1384 					if (params[i].fp != -1) {
1385 						close(params[i].fp);
1386 					}
1387 				}
1388 				efree(params);
1389 				RETURN_FALSE;
1390 			}
1391 			zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
1392 		}
1393 	}
1394 	/* Close cursor, needed for doing multiple selects */
1395 	rc = SQLFreeStmt(result->stmt, SQL_CLOSE);
1396 
1397 	if (rc == SQL_ERROR) {
1398 		odbc_sql_error(result->conn_ptr, result->stmt, "SQLFreeStmt");
1399 	}
1400 
1401 	rc = SQLExecute(result->stmt);
1402 
1403 	result->fetched = 0;
1404 	if (rc == SQL_NEED_DATA) {
1405 		char buf[4096];
1406 		int fp, nbytes;
1407 		while (rc == SQL_NEED_DATA) {
1408 			rc = SQLParamData(result->stmt, (void*)&fp);
1409 			if (rc == SQL_NEED_DATA) {
1410 				while ((nbytes = read(fp, &buf, 4096)) > 0) {
1411 					SQLPutData(result->stmt, (void*)&buf, nbytes);
1412 				}
1413 			}
1414 		}
1415 	} else {
1416 		switch (rc) {
1417 			case SQL_SUCCESS:
1418 				break;
1419 			case SQL_NO_DATA_FOUND:
1420 			case SQL_SUCCESS_WITH_INFO:
1421 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
1422 				break;
1423 			default:
1424 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
1425 				RETVAL_FALSE;
1426 		}
1427 	}
1428 
1429 	if (result->numparams > 0) {
1430 		SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1431 		for(i = 0; i < result->numparams; i++) {
1432 			if (params[i].fp != -1) {
1433 				close(params[i].fp);
1434 			}
1435 		}
1436 		efree(params);
1437 	}
1438 
1439 	if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO || rc == SQL_NO_DATA_FOUND) {
1440 		RETVAL_TRUE;
1441 	}
1442 
1443 	if (result->numcols == 0) {
1444 		SQLNumResultCols(result->stmt, &(result->numcols));
1445 
1446 		if (result->numcols > 0) {
1447 			if (!odbc_bindcols(result TSRMLS_CC)) {
1448 				efree(result);
1449 				RETVAL_FALSE;
1450 			}
1451 		} else {
1452 			result->values = NULL;
1453 		}
1454 	}
1455 }
1456 /* }}} */
1457 
1458 /* {{{ proto string odbc_cursor(resource result_id)
1459    Get cursor name */
PHP_FUNCTION(odbc_cursor)1460 PHP_FUNCTION(odbc_cursor)
1461 {
1462 	zval *pv_res;
1463 	SQLUSMALLINT max_len;
1464 	SQLSMALLINT len;
1465 	char *cursorname;
1466    	odbc_result *result;
1467 	RETCODE rc;
1468 
1469 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1470 		return;
1471 	}
1472 
1473 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1474 
1475 	rc = SQLGetInfo(result->conn_ptr->hdbc,SQL_MAX_CURSOR_NAME_LEN, (void *)&max_len,sizeof(max_len),&len);
1476 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1477 		RETURN_FALSE;
1478 	}
1479 
1480 	if (max_len > 0) {
1481 		cursorname = emalloc(max_len + 1);
1482 		rc = SQLGetCursorName(result->stmt,cursorname,(SQLSMALLINT)max_len,&len);
1483 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1484 			char        state[6];     /* Not used */
1485 	 		SQLINTEGER  error;        /* Not used */
1486 			char        errormsg[SQL_MAX_MESSAGE_LENGTH];
1487 			SQLSMALLINT errormsgsize; /* Not used */
1488 
1489 			SQLError( result->conn_ptr->henv, result->conn_ptr->hdbc,
1490 						result->stmt, state, &error, errormsg,
1491 						sizeof(errormsg)-1, &errormsgsize);
1492 			if (!strncmp(state,"S1015",5)) {
1493 				snprintf(cursorname, max_len+1, "php_curs_%d", (int)result->stmt);
1494 				if (SQLSetCursorName(result->stmt,cursorname,SQL_NTS) != SQL_SUCCESS) {
1495 					odbc_sql_error(result->conn_ptr, result->stmt, "SQLSetCursorName");
1496 					RETVAL_FALSE;
1497 				} else {
1498 					RETVAL_STRING(cursorname,1);
1499 				}
1500 			} else {
1501 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
1502 				RETVAL_FALSE;
1503 			}
1504 		} else {
1505 			RETVAL_STRING(cursorname,1);
1506 		}
1507 		efree(cursorname);
1508 	} else {
1509 		RETVAL_FALSE;
1510 	}
1511 }
1512 /* }}} */
1513 
1514 #ifdef HAVE_SQLDATASOURCES
1515 /* {{{ proto array odbc_data_source(resource connection_id, int fetch_type)
1516    Return information about the currently connected data source */
PHP_FUNCTION(odbc_data_source)1517 PHP_FUNCTION(odbc_data_source)
1518 {
1519 	zval *zv_conn;
1520 	long zv_fetch_type;
1521 	RETCODE rc = 0; /* assume all is good */
1522 	odbc_connection *conn;
1523 	UCHAR server_name[100], desc[200];
1524 	SQLSMALLINT len1=0, len2=0, fetch_type;
1525 
1526 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zv_conn, &zv_fetch_type) == FAILURE) {
1527 		return;
1528 	}
1529 
1530 	fetch_type = (SQLSMALLINT) zv_fetch_type;
1531 
1532 	if (!(fetch_type == SQL_FETCH_FIRST || fetch_type == SQL_FETCH_NEXT)) {
1533 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fetch type (%d)", fetch_type);
1534 		RETURN_FALSE;
1535 	}
1536 
1537 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &zv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1538 
1539 	/* now we have the "connection" lets call the DataSource object */
1540 	rc = SQLDataSources(conn->henv,
1541 			fetch_type,
1542 			server_name,
1543 			(SQLSMALLINT)sizeof(server_name),
1544 			&len1,
1545 			desc,
1546 			(SQLSMALLINT)sizeof(desc),
1547 			&len2);
1548 
1549 	if (rc != SQL_SUCCESS) {
1550 		/* ummm.... he did it */
1551 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLDataSources");
1552 		RETURN_FALSE;
1553 	}
1554 
1555 	if (len1 == 0 || len2 == 0) {
1556 		/* we have a non-valid entry... so stop the looping */
1557 		RETURN_FALSE;
1558 	}
1559 
1560 	array_init(return_value);
1561 
1562 	add_assoc_string_ex(return_value, "server", sizeof("server"), server_name, 1);
1563 	add_assoc_string_ex(return_value, "description", sizeof("description"), desc, 1);
1564 
1565 }
1566 /* }}} */
1567 #endif /* HAVE_SQLDATASOURCES */
1568 
1569 /* {{{ proto resource odbc_exec(resource connection_id, string query [, int flags])
1570    Prepare and execute an SQL statement */
1571 /* XXX Use flags */
PHP_FUNCTION(odbc_exec)1572 PHP_FUNCTION(odbc_exec)
1573 {
1574 	zval *pv_conn;
1575 	long pv_flags;
1576 	char *query;
1577 	int numArgs, query_len;
1578 	odbc_result *result = NULL;
1579 	odbc_connection *conn;
1580 	RETCODE rc;
1581 #ifdef HAVE_SQL_EXTENDED_FETCH
1582 	SQLUINTEGER      scrollopts;
1583 #endif
1584 
1585 	numArgs = ZEND_NUM_ARGS();
1586 
1587 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &pv_conn, &query, &query_len, &pv_flags) == FAILURE) {
1588 		return;
1589 	}
1590 
1591 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1592 
1593 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
1594 
1595 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
1596 	if (rc == SQL_INVALID_HANDLE) {
1597 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
1598 		efree(result);
1599 		RETURN_FALSE;
1600 	}
1601 
1602 	if (rc == SQL_ERROR) {
1603 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
1604 		efree(result);
1605 		RETURN_FALSE;
1606 	}
1607 
1608 #ifdef HAVE_SQL_EXTENDED_FETCH
1609 	/* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
1610 	   whether Driver supports ExtendedFetch */
1611 	rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
1612 	if (rc == SQL_SUCCESS) {
1613 		if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
1614 			/* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
1615 			   type if not possible.
1616 			 */
1617 			SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
1618 		}
1619 	} else {
1620 		result->fetch_abs = 0;
1621 	}
1622 #endif
1623 
1624 	rc = SQLExecDirect(result->stmt, query, SQL_NTS);
1625 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA_FOUND) {
1626 		/* XXX FIXME we should really check out SQLSTATE with SQLError
1627 		 * in case rc is SQL_SUCCESS_WITH_INFO here.
1628 		 */
1629 		odbc_sql_error(conn, result->stmt, "SQLExecDirect");
1630 		SQLFreeStmt(result->stmt, SQL_DROP);
1631 		efree(result);
1632 		RETURN_FALSE;
1633 	}
1634 
1635 	SQLNumResultCols(result->stmt, &(result->numcols));
1636 
1637 	/* For insert, update etc. cols == 0 */
1638 	if (result->numcols > 0) {
1639 		if (!odbc_bindcols(result TSRMLS_CC)) {
1640 			efree(result);
1641 			RETURN_FALSE;
1642 		}
1643 	} else {
1644 		result->values = NULL;
1645 	}
1646 	zend_list_addref(conn->id);
1647 	result->conn_ptr = conn;
1648 	result->fetched = 0;
1649 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1650 }
1651 /* }}} */
1652 
1653 #ifdef PHP_ODBC_HAVE_FETCH_HASH
1654 #define ODBC_NUM  1
1655 #define ODBC_OBJECT  2
1656 
1657 /* {{{ php_odbc_fetch_hash */
php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS,int result_type)1658 static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
1659 {
1660 	int i;
1661 	odbc_result *result;
1662 	RETCODE rc;
1663 	SQLSMALLINT sql_c_type;
1664 	char *buf = NULL;
1665 #ifdef HAVE_SQL_EXTENDED_FETCH
1666 	SQLULEN crow;
1667 	SQLUSMALLINT RowStatus[1];
1668 	SQLLEN rownum;
1669 	zval *pv_res, *tmp;
1670 	long pv_row = -1;
1671 
1672 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
1673 		return;
1674 	}
1675 
1676 	rownum = pv_row;
1677 #else
1678 	zval *pv_res, *tmp;
1679 
1680 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1681 		return;
1682 	}
1683 #endif
1684 
1685 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1686 
1687 	if (result->numcols == 0) {
1688 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1689 		RETURN_FALSE;
1690 	}
1691 
1692 #ifdef HAVE_SQL_EXTENDED_FETCH
1693 	if (result->fetch_abs) {
1694 		if (rownum > 0) {
1695 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1696 		} else {
1697 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1698 		}
1699 	} else
1700 #endif
1701 	rc = SQLFetch(result->stmt);
1702 
1703 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1704 		RETURN_FALSE;
1705 	}
1706 
1707 	array_init(return_value);
1708 
1709 #ifdef HAVE_SQL_EXTENDED_FETCH
1710 	if (rownum > 0 && result->fetch_abs)
1711 		result->fetched = rownum;
1712 	else
1713 #endif
1714 		result->fetched++;
1715 
1716 	for(i = 0; i < result->numcols; i++) {
1717 		ALLOC_INIT_ZVAL(tmp);
1718 		Z_TYPE_P(tmp) = IS_STRING;
1719 		Z_STRLEN_P(tmp) = 0;
1720 		sql_c_type = SQL_C_CHAR;
1721 
1722 		switch(result->values[i].coltype) {
1723 			case SQL_BINARY:
1724 			case SQL_VARBINARY:
1725 			case SQL_LONGVARBINARY:
1726 				if (result->binmode <= 0) {
1727 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1728 					break;
1729 				}
1730 				if (result->binmode == 1) {
1731 					sql_c_type = SQL_C_BINARY;
1732 				}
1733 			case SQL_LONGVARCHAR:
1734 				if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
1735 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1736 					break;
1737 				}
1738 				if (buf == NULL) {
1739 					buf = emalloc(result->longreadlen + 1);
1740 				}
1741 
1742 				rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1), sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
1743 
1744 				if (rc == SQL_ERROR) {
1745 					odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
1746 					efree(buf);
1747 					RETURN_FALSE;
1748 				}
1749 
1750 				if (rc == SQL_SUCCESS_WITH_INFO) {
1751 					Z_STRLEN_P(tmp) = result->longreadlen;
1752 				} else if (result->values[i].vallen == SQL_NULL_DATA) {
1753 					ZVAL_NULL(tmp);
1754 					break;
1755 				} else {
1756 					Z_STRLEN_P(tmp) = result->values[i].vallen;
1757 				}
1758 				Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
1759 				break;
1760 
1761 			default:
1762 				if (result->values[i].vallen == SQL_NULL_DATA) {
1763 					ZVAL_NULL(tmp);
1764 					break;
1765 				}
1766 				Z_STRLEN_P(tmp) = result->values[i].vallen;
1767 				Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
1768 				break;
1769 		}
1770 
1771 		if (result_type & ODBC_NUM) {
1772 			zend_hash_index_update(Z_ARRVAL_P(return_value), i, &tmp, sizeof(zval *), NULL);
1773 		} else {
1774 			if (!*(result->values[i].name)) {
1775 				zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(tmp),	Z_STRLEN_P(tmp)+1, &tmp, sizeof(zval *), NULL);
1776 			} else {
1777 				zend_hash_update(Z_ARRVAL_P(return_value), result->values[i].name, strlen(result->values[i].name)+1, &tmp, sizeof(zval *), NULL);
1778 			}
1779 		}
1780 	}
1781 	if (buf) {
1782 		efree(buf);
1783 	}
1784 }
1785 /* }}} */
1786 
1787 
1788 /* {{{ proto object odbc_fetch_object(int result [, int rownumber])
1789    Fetch a result row as an object */
PHP_FUNCTION(odbc_fetch_object)1790 PHP_FUNCTION(odbc_fetch_object)
1791 {
1792 	php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
1793 	if (Z_TYPE_P(return_value) == IS_ARRAY) {
1794 		object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1795 	}
1796 }
1797 /* }}} */
1798 
1799 /* {{{ proto array odbc_fetch_array(int result [, int rownumber])
1800    Fetch a result row as an associative array */
PHP_FUNCTION(odbc_fetch_array)1801 PHP_FUNCTION(odbc_fetch_array)
1802 {
1803 	php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
1804 }
1805 /* }}} */
1806 #endif
1807 
1808 /* {{{ proto int odbc_fetch_into(resource result_id, array &result_array, [, int rownumber])
1809    Fetch one result row into an array */
PHP_FUNCTION(odbc_fetch_into)1810 PHP_FUNCTION(odbc_fetch_into)
1811 {
1812 	int i;
1813 	odbc_result *result;
1814 	RETCODE rc;
1815 	SQLSMALLINT sql_c_type;
1816 	char *buf = NULL;
1817 	zval *pv_res, **pv_res_arr, *tmp;
1818 #ifdef HAVE_SQL_EXTENDED_FETCH
1819 	long pv_row = 0;
1820 	SQLULEN crow;
1821 	SQLUSMALLINT RowStatus[1];
1822 	SQLLEN rownum = -1;
1823 #endif /* HAVE_SQL_EXTENDED_FETCH */
1824 
1825 #ifdef HAVE_SQL_EXTENDED_FETCH
1826 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) {
1827 		return;
1828 	}
1829 
1830 	rownum = pv_row;
1831 #else
1832 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_res_arr) == FAILURE) {
1833 		return;
1834 	}
1835 #endif /* HAVE_SQL_EXTENDED_FETCH */
1836 
1837 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1838 
1839 	if (result->numcols == 0) {
1840 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1841 		RETURN_FALSE;
1842 	}
1843 
1844 	if (Z_TYPE_PP(pv_res_arr) != IS_ARRAY) {
1845 		array_init(*pv_res_arr);
1846 	}
1847 
1848 #ifdef HAVE_SQL_EXTENDED_FETCH
1849 	if (result->fetch_abs) {
1850 		if (rownum > 0) {
1851 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1852 		} else {
1853 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1854 		}
1855 	} else
1856 #endif
1857 		rc = SQLFetch(result->stmt);
1858 
1859 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1860 		RETURN_FALSE;
1861 	}
1862 
1863 #ifdef HAVE_SQL_EXTENDED_FETCH
1864 	if (rownum > 0 && result->fetch_abs)
1865 		result->fetched = rownum;
1866 	else
1867 #endif
1868 		result->fetched++;
1869 
1870 	for(i = 0; i < result->numcols; i++) {
1871 		MAKE_STD_ZVAL(tmp);
1872 		Z_TYPE_P(tmp) = IS_STRING;
1873 		Z_STRLEN_P(tmp) = 0;
1874 		sql_c_type = SQL_C_CHAR;
1875 
1876 		switch(result->values[i].coltype) {
1877 			case SQL_BINARY:
1878 			case SQL_VARBINARY:
1879 			case SQL_LONGVARBINARY:
1880 				if (result->binmode <= 0) {
1881 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1882 					break;
1883 				}
1884 				if (result->binmode == 1) sql_c_type = SQL_C_BINARY;
1885 			case SQL_LONGVARCHAR:
1886 				if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
1887 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1888 					break;
1889 				}
1890 
1891 				if (buf == NULL) {
1892 					buf = emalloc(result->longreadlen + 1);
1893 				}
1894 				rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
1895 
1896 				if (rc == SQL_ERROR) {
1897 					odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
1898 					efree(buf);
1899 					RETURN_FALSE;
1900 				}
1901 				if (rc == SQL_SUCCESS_WITH_INFO) {
1902 					Z_STRLEN_P(tmp) = result->longreadlen;
1903 				} else if (result->values[i].vallen == SQL_NULL_DATA) {
1904 					ZVAL_NULL(tmp);
1905 					break;
1906 				} else {
1907 					Z_STRLEN_P(tmp) = result->values[i].vallen;
1908 				}
1909 				Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
1910 				break;
1911 
1912 			default:
1913 				if (result->values[i].vallen == SQL_NULL_DATA) {
1914 					ZVAL_NULL(tmp);
1915 					break;
1916 				}
1917 				Z_STRLEN_P(tmp) = result->values[i].vallen;
1918 				Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
1919 				break;
1920 		}
1921 		zend_hash_index_update(Z_ARRVAL_PP(pv_res_arr), i, &tmp, sizeof(zval *), NULL);
1922 	}
1923 	if (buf) efree(buf);
1924 	RETURN_LONG(result->numcols);
1925 }
1926 /* }}} */
1927 
1928 /* {{{ proto bool solid_fetch_prev(resource result_id)
1929    */
1930 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
PHP_FUNCTION(solid_fetch_prev)1931 PHP_FUNCTION(solid_fetch_prev)
1932 {
1933 	odbc_result *result;
1934 	RETCODE rc;
1935 	zval *pv_res;
1936 
1937 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1938 		return;
1939 	}
1940 
1941 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1942 	if (result->numcols == 0) {
1943 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1944 		RETURN_FALSE;
1945 	}
1946 	rc = SQLFetchPrev(result->stmt);
1947 
1948 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1949 		RETURN_FALSE;
1950 	}
1951 
1952 	if (result->fetched > 1) {
1953 		result->fetched--;
1954 	}
1955 
1956 	RETURN_TRUE;
1957 }
1958 #endif
1959 /* }}} */
1960 
1961 /* {{{ proto bool odbc_fetch_row(resource result_id [, int row_number])
1962    Fetch a row */
PHP_FUNCTION(odbc_fetch_row)1963 PHP_FUNCTION(odbc_fetch_row)
1964 {
1965 	SQLLEN rownum;
1966 	odbc_result *result;
1967 	RETCODE rc;
1968 	zval *pv_res;
1969 	long pv_row = 1;
1970 #ifdef HAVE_SQL_EXTENDED_FETCH
1971 	SQLULEN crow;
1972 	SQLUSMALLINT RowStatus[1];
1973 #endif
1974 
1975 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
1976 		return;
1977 	}
1978 
1979 	rownum = pv_row;
1980 
1981 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1982 
1983 	if (result->numcols == 0) {
1984 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1985 		RETURN_FALSE;
1986 	}
1987 
1988 #ifdef HAVE_SQL_EXTENDED_FETCH
1989 	if (result->fetch_abs) {
1990 		if (ZEND_NUM_ARGS() > 1) {
1991 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1992 		} else {
1993 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1994 		}
1995 	} else
1996 #endif
1997 		rc = SQLFetch(result->stmt);
1998 
1999 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2000 		RETURN_FALSE;
2001 	}
2002 
2003 	if (ZEND_NUM_ARGS() > 1) {
2004 		result->fetched = rownum;
2005 	} else {
2006 		result->fetched++;
2007 	}
2008 
2009 	RETURN_TRUE;
2010 }
2011 /* }}} */
2012 
2013 /* {{{ proto mixed odbc_result(resource result_id, mixed field)
2014    Get result data */
PHP_FUNCTION(odbc_result)2015 PHP_FUNCTION(odbc_result)
2016 {
2017 	char *field;
2018 	int field_ind;
2019 	SQLSMALLINT sql_c_type = SQL_C_CHAR;
2020 	odbc_result *result;
2021 	int i = 0;
2022 	RETCODE rc;
2023 	SQLLEN	fieldsize;
2024 	zval *pv_res, **pv_field;
2025 #ifdef HAVE_SQL_EXTENDED_FETCH
2026 	SQLULEN crow;
2027 	SQLUSMALLINT RowStatus[1];
2028 #endif
2029 
2030 	field_ind = -1;
2031 	field = NULL;
2032 
2033 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_field) == FAILURE) {
2034 		return;
2035 	}
2036 
2037 	if (Z_TYPE_PP(pv_field) == IS_STRING) {
2038 		field = Z_STRVAL_PP(pv_field);
2039 	} else {
2040 		convert_to_long_ex(pv_field);
2041 		field_ind = Z_LVAL_PP(pv_field) - 1;
2042 	}
2043 
2044 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2045 
2046 	if ((result->numcols == 0)) {
2047 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2048 		RETURN_FALSE;
2049 	}
2050 
2051 	/* get field index if the field parameter was a string */
2052 	if (field != NULL) {
2053 		if (result->values == NULL) {
2054 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set contains no data");
2055 			RETURN_FALSE;
2056 		}
2057 
2058 		for(i = 0; i < result->numcols; i++) {
2059 			if (!strcasecmp(result->values[i].name, field)) {
2060 				field_ind = i;
2061 				break;
2062 			}
2063 		}
2064 
2065 		if (field_ind < 0) {
2066 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field %s not found", field);
2067 			RETURN_FALSE;
2068 		}
2069 	} else {
2070 		/* check for limits of field_ind if the field parameter was an int */
2071 		if (field_ind >= result->numcols || field_ind < 0) {
2072 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index is larger than the number of fields");
2073 			RETURN_FALSE;
2074 		}
2075 	}
2076 
2077 	if (result->fetched == 0) {
2078 		/* User forgot to call odbc_fetch_row(), or wants to reload the results, do it now */
2079 #ifdef HAVE_SQL_EXTENDED_FETCH
2080 		if (result->fetch_abs)
2081 			rc = SQLExtendedFetch(result->stmt, SQL_FETCH_NEXT, 1, &crow,RowStatus);
2082 		else
2083 #endif
2084 			rc = SQLFetch(result->stmt);
2085 
2086 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2087 			RETURN_FALSE;
2088 		}
2089 
2090 		result->fetched++;
2091 	}
2092 
2093 	switch(result->values[field_ind].coltype) {
2094 		case SQL_BINARY:
2095 		case SQL_VARBINARY:
2096 		case SQL_LONGVARBINARY:
2097 			if (result->binmode <= 1) {
2098 				sql_c_type = SQL_C_BINARY;
2099 			}
2100 			if (result->binmode <= 0) {
2101 				break;
2102 			}
2103 		case SQL_LONGVARCHAR:
2104 			if (IS_SQL_LONG(result->values[field_ind].coltype)) {
2105 				if (result->longreadlen <= 0) {
2106 				   break;
2107 				} else {
2108 				   fieldsize = result->longreadlen;
2109 				}
2110 			} else {
2111 			   SQLColAttributes(result->stmt, (SQLUSMALLINT)(field_ind + 1),
2112 					   			(SQLUSMALLINT)((sql_c_type == SQL_C_BINARY) ? SQL_COLUMN_LENGTH :
2113 					   			SQL_COLUMN_DISPLAY_SIZE),
2114 					   			NULL, 0, NULL, &fieldsize);
2115 			}
2116 			/* For char data, the length of the returned string will be longreadlen - 1 */
2117 			fieldsize = (result->longreadlen <= 0) ? 4096 : result->longreadlen;
2118 			field = emalloc(fieldsize);
2119 
2120 		/* SQLGetData will truncate CHAR data to fieldsize - 1 bytes and append \0.
2121 		 * For binary data it is truncated to fieldsize bytes.
2122 		 */
2123 			rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1), sql_c_type,
2124 							field, fieldsize, &result->values[field_ind].vallen);
2125 
2126 			if (rc == SQL_ERROR) {
2127 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2128 				efree(field);
2129 				RETURN_FALSE;
2130 			}
2131 
2132 			if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2133 				efree(field);
2134 				RETURN_NULL();
2135 			} else if (rc == SQL_NO_DATA_FOUND) {
2136 				efree(field);
2137 				RETURN_FALSE;
2138 			}
2139 			/* Reduce fieldlen by 1 if we have char data. One day we might
2140 			   have binary strings... */
2141 			if (result->values[field_ind].coltype == SQL_LONGVARCHAR) {
2142 				fieldsize -= 1;
2143 			}
2144 			/* Don't duplicate result, saves one emalloc.
2145 			   For SQL_SUCCESS, the length is in vallen.
2146 			 */
2147 			RETURN_STRINGL(field, (rc == SQL_SUCCESS_WITH_INFO) ? fieldsize : result->values[field_ind].vallen, 0);
2148 			break;
2149 
2150 		default:
2151 			if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2152 				RETURN_NULL();
2153 			} else {
2154 				RETURN_STRINGL(result->values[field_ind].value, result->values[field_ind].vallen, 1);
2155 			}
2156 			break;
2157 	}
2158 
2159 /* If we come here, output unbound LONG and/or BINARY column data to the client */
2160 
2161 	/* We emalloc 1 byte more for SQL_C_CHAR (trailing \0) */
2162 	fieldsize = (sql_c_type == SQL_C_CHAR) ? 4096 : 4095;
2163 	field = emalloc(fieldsize);
2164 
2165 	/* Call SQLGetData() until SQL_SUCCESS is returned */
2166 	while(1) {
2167 		rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1),sql_c_type, field, fieldsize, &result->values[field_ind].vallen);
2168 
2169 		if (rc == SQL_ERROR) {
2170 			odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2171 			efree(field);
2172 			RETURN_FALSE;
2173 		}
2174 
2175 		if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2176 			efree(field);
2177 			RETURN_NULL();
2178 		}
2179 		/* chop the trailing \0 by outputing only 4095 bytes */
2180 		PHPWRITE(field,(rc == SQL_SUCCESS_WITH_INFO) ? 4095 : result->values[field_ind].vallen);
2181 
2182 		if (rc == SQL_SUCCESS) { /* no more data avail */
2183 			efree(field);
2184 			RETURN_TRUE;
2185 		}
2186 	}
2187 	RETURN_TRUE;
2188 }
2189 /* }}} */
2190 
2191 /* {{{ proto int odbc_result_all(resource result_id [, string format])
2192    Print result as HTML table */
PHP_FUNCTION(odbc_result_all)2193 PHP_FUNCTION(odbc_result_all)
2194 {
2195 	char *buf = NULL;
2196 	odbc_result *result;
2197 	RETCODE rc;
2198 	zval *pv_res;
2199 	char *pv_format = NULL;
2200 	int i, pv_format_len = 0;
2201 	SQLSMALLINT sql_c_type;
2202 #ifdef HAVE_SQL_EXTENDED_FETCH
2203 	SQLULEN crow;
2204 	SQLUSMALLINT RowStatus[1];
2205 #endif
2206 
2207 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s", &pv_res, &pv_format, &pv_format_len) == FAILURE) {
2208 		return;
2209 	}
2210 
2211 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2212 
2213 	if (result->numcols == 0) {
2214 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2215 		RETURN_FALSE;
2216 	}
2217 #ifdef HAVE_SQL_EXTENDED_FETCH
2218 	if (result->fetch_abs)
2219 		rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2220 	else
2221 #endif
2222 		rc = SQLFetch(result->stmt);
2223 
2224 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2225 		php_printf("<h2>No rows found</h2>\n");
2226 		RETURN_LONG(0);
2227 	}
2228 
2229 	/* Start table tag */
2230 	if (ZEND_NUM_ARGS() == 1) {
2231 		php_printf("<table><tr>");
2232 	} else {
2233 		php_printf("<table %s ><tr>", pv_format);
2234 	}
2235 
2236 	for (i = 0; i < result->numcols; i++) {
2237 		php_printf("<th>%s</th>", result->values[i].name);
2238 	}
2239 
2240 	php_printf("</tr>\n");
2241 
2242 	while(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
2243 		result->fetched++;
2244 		php_printf("<tr>");
2245 		for(i = 0; i < result->numcols; i++) {
2246 			sql_c_type = SQL_C_CHAR;
2247 			switch(result->values[i].coltype) {
2248 				case SQL_BINARY:
2249 				case SQL_VARBINARY:
2250 				case SQL_LONGVARBINARY:
2251 					if (result->binmode <= 0) {
2252 						php_printf("<td>Not printable</td>");
2253 						break;
2254 					}
2255 					if (result->binmode <= 1) sql_c_type = SQL_C_BINARY;
2256 				case SQL_LONGVARCHAR:
2257 					if (IS_SQL_LONG(result->values[i].coltype) &&
2258 						result->longreadlen <= 0) {
2259 						php_printf("<td>Not printable</td>");
2260 						break;
2261 					}
2262 
2263 					if (buf == NULL) {
2264 						buf = emalloc(result->longreadlen);
2265 					}
2266 
2267 					rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen, &result->values[i].vallen);
2268 
2269 					php_printf("<td>");
2270 
2271 					if (rc == SQL_ERROR) {
2272 						odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2273 						php_printf("</td></tr></table>");
2274 						efree(buf);
2275 						RETURN_FALSE;
2276 					}
2277 					if (rc == SQL_SUCCESS_WITH_INFO) {
2278 						PHPWRITE(buf, result->longreadlen);
2279 					} else if (result->values[i].vallen == SQL_NULL_DATA) {
2280 						php_printf("<td>NULL</td>");
2281 						break;
2282 					} else {
2283 						PHPWRITE(buf, result->values[i].vallen);
2284 					}
2285 					php_printf("</td>");
2286 					break;
2287 				default:
2288 					if (result->values[i].vallen == SQL_NULL_DATA) {
2289 						php_printf("<td>NULL</td>");
2290 					} else {
2291 						php_printf("<td>%s</td>", result->values[i].value);
2292 					}
2293 					break;
2294 			}
2295 		}
2296    		php_printf("</tr>\n");
2297 
2298 #ifdef HAVE_SQL_EXTENDED_FETCH
2299 		if (result->fetch_abs)
2300 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2301 		else
2302 #endif
2303 			rc = SQLFetch(result->stmt);
2304 	}
2305 	php_printf("</table>\n");
2306 	if (buf) efree(buf);
2307 	RETURN_LONG(result->fetched);
2308 }
2309 /* }}} */
2310 
2311 /* {{{ proto bool odbc_free_result(resource result_id)
2312    Free resources associated with a result */
PHP_FUNCTION(odbc_free_result)2313 PHP_FUNCTION(odbc_free_result)
2314 {
2315 	zval *pv_res;
2316 	odbc_result *result;
2317 	int i;
2318 
2319 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2320 		return;
2321 	}
2322 
2323 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2324 	if (result->values) {
2325 		for (i = 0; i < result->numcols; i++) {
2326 			if (result->values[i].value) {
2327 				efree(result->values[i].value);
2328 			}
2329 		}
2330 		efree(result->values);
2331 		result->values = NULL;
2332 	}
2333 
2334 	zend_list_delete(Z_LVAL_P(pv_res));
2335 
2336 	RETURN_TRUE;
2337 }
2338 /* }}} */
2339 
2340 /* {{{ proto resource odbc_connect(string DSN, string user, string password [, int cursor_option])
2341    Connect to a datasource */
PHP_FUNCTION(odbc_connect)2342 PHP_FUNCTION(odbc_connect)
2343 {
2344 	odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2345 }
2346 /* }}} */
2347 
2348 /* {{{ proto resource odbc_pconnect(string DSN, string user, string password [, int cursor_option])
2349    Establish a persistent connection to a datasource */
PHP_FUNCTION(odbc_pconnect)2350 PHP_FUNCTION(odbc_pconnect)
2351 {
2352 	odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2353 }
2354 /* }}} */
2355 
2356 /* {{{ odbc_sqlconnect */
odbc_sqlconnect(odbc_connection ** conn,char * db,char * uid,char * pwd,int cur_opt,int persistent TSRMLS_DC)2357 int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int cur_opt, int persistent TSRMLS_DC)
2358 {
2359 	RETCODE rc;
2360 
2361 	*conn = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent);
2362 	(*conn)->persistent = persistent;
2363 	SQLAllocEnv(&((*conn)->henv));
2364 	SQLAllocConnect((*conn)->henv, &((*conn)->hdbc));
2365 
2366 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
2367 	SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION,
2368 			SQL_SOLID_XLATOPT_NOCNV);
2369 #endif
2370 #ifdef HAVE_ODBC_ROUTER
2371 	{
2372 #define CONNSTRSIZE 2048
2373 	 char *lpszConnStr = emalloc(CONNSTRSIZE);
2374 	 if (lpszConnStr && db) {
2375 		 short cbszConnStr;
2376 		 if (strstr(db, ";")) {
2377 			 /* the caller has apparently passed a connection-string */
2378 			 if (strstr(db, "uid") || strstr(db, "UID")) {
2379 				 uid = NULL;
2380 			 }
2381 			 if (strstr(db, "pwd") || strstr(db, "PWD")) {
2382 				 pwd = NULL;
2383 			 }
2384 			 strlcpy( lpszConnStr, db, CONNSTRSIZE);
2385 		 }
2386 		 else {
2387 			 strcpy(lpszConnStr, "DSN=");
2388 			 strlcat(lpszConnStr, db, CONNSTRSIZE);
2389 		 }
2390 		 if (uid) {
2391 			 if (uid[0]) {
2392 				 strlcat(lpszConnStr, ";UID=", CONNSTRSIZE);
2393 				 strlcat(lpszConnStr, uid, CONNSTRSIZE);
2394 				 strlcat(lpszConnStr, ";", CONNSTRSIZE);
2395 			 }
2396 			 if (pwd) {
2397 				 if (pwd[0]) {
2398 					 strlcat(lpszConnStr, "PWD=", CONNSTRSIZE);
2399 					 strlcat(lpszConnStr, pwd, CONNSTRSIZE);
2400 					 strlcat(lpszConnStr, ";", CONNSTRSIZE);
2401 				 }
2402 			 }
2403 		 }
2404 		 rc = SQLDriverConnect((*conn)->hdbc, NULL, lpszConnStr, SQL_NTS, lpszConnStr, CONNSTRSIZE, &cbszConnStr, SQL_DRIVER_NOPROMPT);
2405 		 efree(lpszConnStr);
2406 	 }
2407 	}
2408 #else
2409 #ifdef HAVE_OPENLINK
2410 	{
2411 		char dsnbuf[1024];
2412 		short dsnbuflen;
2413 
2414 		rc = SQLDriverConnect((*conn)->hdbc, NULL, db, SQL_NTS,	dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
2415 	}
2416 #else
2417 	if (cur_opt != SQL_CUR_DEFAULT) {
2418 		rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt);
2419 		if (rc != SQL_SUCCESS) {  /* && rc != SQL_SUCCESS_WITH_INFO ? */
2420 			odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption");
2421 			SQLFreeConnect((*conn)->hdbc);
2422 			pefree(*conn, persistent);
2423 			return FALSE;
2424 		}
2425 	}
2426 /*  Possible fix for bug #10250
2427  *  Needs testing on UnixODBC < 2.0.5 though. */
2428 #if defined(HAVE_EMPRESS) || defined(HAVE_UNIXODBC) || defined(PHP_WIN32) || defined (HAVE_IODBC)
2429 /* *  Uncomment the line above, and comment line below to fully test
2430  * #ifdef HAVE_EMPRESS */
2431 	{
2432 		int     direct = 0;
2433 		char    dsnbuf[1024];
2434 		short   dsnbuflen;
2435 		char    *ldb = 0;
2436 		int		ldb_len = 0;
2437 
2438 		if (strstr((char*)db, ";")) {
2439 			direct = 1;
2440 			if (uid && !strstr ((char*)db, "uid") && !strstr((char*)db, "UID")) {
2441 				spprintf(&ldb, 0, "%s;UID=%s;PWD=%s", db, uid, pwd);
2442 			} else {
2443 				ldb_len = strlen(db)+1;
2444 				ldb = (char*) emalloc(ldb_len);
2445 				memcpy(ldb, db, ldb_len);
2446 			}
2447 		}
2448 
2449 		if (direct) {
2450 			rc = SQLDriverConnect((*conn)->hdbc, NULL, ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
2451 		} else {
2452 			rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
2453 		}
2454 
2455 		if (ldb) {
2456 			efree(ldb);
2457 		}
2458 	}
2459 #else
2460 	rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
2461 #endif
2462 #endif
2463 #endif
2464 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2465 		odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLConnect");
2466 		SQLFreeConnect((*conn)->hdbc);
2467 		pefree((*conn), persistent);
2468 		return FALSE;
2469 	}
2470 /*	(*conn)->open = 1;*/
2471 	return TRUE;
2472 }
2473 /* }}} */
2474 
2475 /* Persistent connections: two list-types le_pconn, le_conn and a plist
2476  * where hashed connection info is stored together with index pointer to
2477  * the actual link of type le_pconn in the list. Only persistent
2478  * connections get hashed up. Normal connections use existing pconnections.
2479  * Maybe this has to change with regard to transactions on pconnections?
2480  * Possibly set autocommit to on on request shutdown.
2481  *
2482  * We do have to hash non-persistent connections, and reuse connections.
2483  * In the case where two connects were being made, without closing the first
2484  * connect, access violations were occuring.  This is because some of the
2485  * "globals" in this module should actualy be per-connection variables.  I
2486  * simply fixed things to get them working for now.  Shane
2487  */
2488 /* {{{ odbc_do_connect */
odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent)2489 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
2490 {
2491 	char *db, *uid, *pwd;
2492 	int db_len, uid_len, pwd_len;
2493 	long pv_opt = SQL_CUR_DEFAULT;
2494 	odbc_connection *db_conn;
2495 	char *hashed_details;
2496 	int hashed_len, cur_opt;
2497 
2498 	/*  Now an optional 4th parameter specifying the cursor type
2499 	 *  defaulting to the cursors default
2500 	 */
2501 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &db, &db_len, &uid, &uid_len, &pwd, &pwd_len, &pv_opt) == FAILURE) {
2502 		return;
2503 	}
2504 
2505 	cur_opt = pv_opt;
2506 
2507 	if (ZEND_NUM_ARGS() > 3) {
2508 		/* Confirm the cur_opt range */
2509 		if (! (cur_opt == SQL_CUR_USE_IF_NEEDED ||
2510 			cur_opt == SQL_CUR_USE_ODBC ||
2511 			cur_opt == SQL_CUR_USE_DRIVER ||
2512 			cur_opt == SQL_CUR_DEFAULT) ) {
2513 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Cursor type (%d)", cur_opt);
2514 			RETURN_FALSE;
2515 		}
2516 	}
2517 
2518 	if (ODBCG(allow_persistent) <= 0) {
2519 		persistent = 0;
2520 	}
2521 
2522 	hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt);
2523 
2524 	/* FIXME the idea of checking to see if our connection is already persistent
2525 		is good, but it adds a lot of overhead to non-persistent connections.  We
2526 		should look and see if we can fix that somehow */
2527 	/* try to find if we already have this link in our persistent list,
2528 	 * no matter if it is to be persistent or not
2529 	 */
2530 
2531 try_and_get_another_connection:
2532 
2533 	if (persistent) {
2534 		zend_rsrc_list_entry *le;
2535 
2536 		/* the link is not in the persistent list */
2537 		if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_len + 1, (void **) &le)	== FAILURE) {
2538 			zend_rsrc_list_entry new_le;
2539 
2540 			if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
2541 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", ODBCG(num_links));
2542 				efree(hashed_details);
2543 				RETURN_FALSE;
2544 			}
2545 			if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) {
2546 				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open persistent links (%ld)", ODBCG(num_persistent));
2547 				efree(hashed_details);
2548 				RETURN_FALSE;
2549 			}
2550 
2551 			if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1 TSRMLS_CC)) {
2552 				efree(hashed_details);
2553 				RETURN_FALSE;
2554 			}
2555 
2556 			Z_TYPE(new_le) = le_pconn;
2557 			new_le.ptr = db_conn;
2558 			if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_len + 1, &new_le,
2559 						sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
2560 				free(db_conn);
2561 				efree(hashed_details);
2562 				RETURN_FALSE;
2563 			}
2564 			ODBCG(num_persistent)++;
2565 			ODBCG(num_links)++;
2566 			db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
2567 		} else { /* found connection */
2568 			if (Z_TYPE_P(le) != le_pconn) {
2569 				RETURN_FALSE;
2570 			}
2571 			/*
2572 			 * check to see if the connection is still valid
2573 			 */
2574 			db_conn = (odbc_connection *)le->ptr;
2575 
2576 			/*
2577 			 * check to see if the connection is still in place (lurcher)
2578 			 */
2579 			if(ODBCG(check_persistent)){
2580 				RETCODE ret;
2581 				UCHAR d_name[32];
2582 				SQLSMALLINT len;
2583 
2584 				ret = SQLGetInfo(db_conn->hdbc,
2585 					SQL_DATA_SOURCE_READ_ONLY,
2586 					d_name, sizeof(d_name), &len);
2587 
2588 				if(ret != SQL_SUCCESS || len == 0) {
2589 					zend_hash_del(&EG(persistent_list), hashed_details, hashed_len + 1);
2590 					/* Commented out to fix a possible double closure error
2591 					 * when working with persistent connections as submitted by
2592 					 * bug #15758
2593 					 *
2594 					 * safe_odbc_disconnect(db_conn->hdbc);
2595 					 * SQLFreeConnect(db_conn->hdbc);
2596 					 */
2597 					goto try_and_get_another_connection;
2598 				}
2599 			}
2600 		}
2601 		db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
2602 	} else { /* non persistent */
2603 		zend_rsrc_list_entry *index_ptr, new_index_ptr;
2604 
2605 		if (zend_hash_find(&EG(regular_list), hashed_details, hashed_len + 1, (void **) &index_ptr) == SUCCESS) {
2606 			int type, conn_id;
2607 			void *ptr;
2608 
2609 			if (Z_TYPE_P(index_ptr) != le_index_ptr) {
2610 				RETURN_FALSE;
2611 			}
2612 			conn_id = (int)index_ptr->ptr;
2613 			ptr = zend_list_find(conn_id, &type);   /* check if the connection is still there */
2614 
2615 			if (ptr && (type == le_conn || type == le_pconn)) {
2616 				zend_list_addref(conn_id);
2617 				Z_LVAL_P(return_value) = conn_id;
2618 				Z_TYPE_P(return_value) = IS_RESOURCE;
2619 				efree(hashed_details);
2620 				return;
2621 			} else {
2622 				zend_hash_del(&EG(regular_list), hashed_details, hashed_len + 1);
2623 			}
2624 		}
2625 		if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
2626 			php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open connections (%ld)",ODBCG(num_links));
2627 			efree(hashed_details);
2628 			RETURN_FALSE;
2629 		}
2630 
2631 		if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0 TSRMLS_CC)) {
2632 			efree(hashed_details);
2633 			RETURN_FALSE;
2634 		}
2635 		db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_conn);
2636 		new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
2637 		Z_TYPE(new_index_ptr) = le_index_ptr;
2638 
2639 		if (zend_hash_update(&EG(regular_list), hashed_details, hashed_len + 1, (void *) &new_index_ptr,
2640 				   sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
2641 			efree(hashed_details);
2642 			RETURN_FALSE;
2643 			/* XXX Free Connection */
2644 		}
2645 		ODBCG(num_links)++;
2646 	}
2647 	efree(hashed_details);
2648 }
2649 /* }}} */
2650 
2651 /* {{{ proto void odbc_close(resource connection_id)
2652    Close an ODBC connection */
PHP_FUNCTION(odbc_close)2653 PHP_FUNCTION(odbc_close)
2654 {
2655 	zval *pv_conn;
2656 	void *ptr;
2657 	odbc_connection *conn;
2658 	odbc_result *res;
2659 	int nument;
2660 	int i;
2661 	int type;
2662 	int is_pconn = 0;
2663 	int found_resource_type = le_conn;
2664 
2665 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
2666 		return;
2667 	}
2668 
2669 	conn = (odbc_connection *) zend_fetch_resource(&pv_conn TSRMLS_CC, -1, "ODBC-Link", &found_resource_type, 2, le_conn, le_pconn);
2670 	if (found_resource_type==le_pconn) {
2671 		is_pconn = 1;
2672 	}
2673 
2674 	nument = zend_hash_next_free_element(&EG(regular_list));
2675 
2676 	for(i = 1; i < nument; i++){
2677 		ptr = zend_list_find(i, &type);
2678 		if(ptr && (type == le_result)){
2679 			res = (odbc_result *)ptr;
2680 			if(res->conn_ptr == conn){
2681 				zend_list_delete(i);
2682 			}
2683 		}
2684 	}
2685 
2686 	zend_list_delete(Z_LVAL_P(pv_conn));
2687 
2688 	if(is_pconn){
2689 		zend_hash_apply_with_argument(&EG(persistent_list),	(apply_func_arg_t) _close_pconn_with_id, (void *) &(Z_LVAL_P(pv_conn)) TSRMLS_CC);
2690 	}
2691 }
2692 /* }}} */
2693 
2694 /* {{{ proto int odbc_num_rows(resource result_id)
2695    Get number of rows in a result */
PHP_FUNCTION(odbc_num_rows)2696 PHP_FUNCTION(odbc_num_rows)
2697 {
2698 	odbc_result *result;
2699 	SQLLEN rows;
2700 	zval *pv_res;
2701 
2702 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2703 		return;
2704 	}
2705 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2706 	SQLRowCount(result->stmt, &rows);
2707 	RETURN_LONG(rows);
2708 }
2709 /* }}} */
2710 
2711 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
2712 /* {{{ proto bool odbc_next_result(resource result_id)
2713    Checks if multiple results are avaiable */
PHP_FUNCTION(odbc_next_result)2714 PHP_FUNCTION(odbc_next_result)
2715 {
2716 	odbc_result *result;
2717 	zval *pv_res;
2718 	int rc, i;
2719 
2720 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2721 		return;
2722 	}
2723 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2724 
2725 	if (result->values) {
2726 		for(i = 0; i < result->numcols; i++) {
2727 			if (result->values[i].value) {
2728 				efree(result->values[i].value);
2729 			}
2730 		}
2731 		efree(result->values);
2732 		result->values = NULL;
2733 	}
2734 
2735 	result->fetched = 0;
2736 	rc = SQLMoreResults(result->stmt);
2737 	if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS) {
2738 		rc = SQLFreeStmt(result->stmt, SQL_UNBIND);
2739 		SQLNumParams(result->stmt, &(result->numparams));
2740 		SQLNumResultCols(result->stmt, &(result->numcols));
2741 
2742 		if (result->numcols > 0) {
2743 			if (!odbc_bindcols(result TSRMLS_CC)) {
2744 				efree(result);
2745 				RETVAL_FALSE;
2746 			}
2747 		} else {
2748 			result->values = NULL;
2749 		}
2750 		RETURN_TRUE;
2751 	} else if (rc == SQL_NO_DATA_FOUND) {
2752 		RETURN_FALSE;
2753 	} else {
2754 		odbc_sql_error(result->conn_ptr, result->stmt, "SQLMoreResults");
2755 		RETURN_FALSE;
2756 	}
2757 }
2758 /* }}} */
2759 #endif
2760 
2761 /* {{{ proto int odbc_num_fields(resource result_id)
2762    Get number of columns in a result */
PHP_FUNCTION(odbc_num_fields)2763 PHP_FUNCTION(odbc_num_fields)
2764 {
2765 	odbc_result *result;
2766 	zval *pv_res;
2767 
2768 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2769 		return;
2770 	}
2771 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2772 	RETURN_LONG(result->numcols);
2773 }
2774 /* }}} */
2775 
2776 /* {{{ proto string odbc_field_name(resource result_id, int field_number)
2777    Get a column name */
PHP_FUNCTION(odbc_field_name)2778 PHP_FUNCTION(odbc_field_name)
2779 {
2780 	odbc_result *result;
2781 	zval *pv_res;
2782 	long pv_num;
2783 
2784 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
2785 		return;
2786 	}
2787 
2788 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2789 
2790 	if (result->numcols == 0) {
2791 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2792 		RETURN_FALSE;
2793 	}
2794 
2795 	if (pv_num > result->numcols) {
2796 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
2797 		RETURN_FALSE;
2798 	}
2799 
2800 	if (pv_num < 1) {
2801 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
2802 		RETURN_FALSE;
2803 	}
2804 
2805 	RETURN_STRING(result->values[pv_num - 1].name, 1);
2806 }
2807 /* }}} */
2808 
2809 /* {{{ proto string odbc_field_type(resource result_id, int field_number)
2810    Get the datatype of a column */
PHP_FUNCTION(odbc_field_type)2811 PHP_FUNCTION(odbc_field_type)
2812 {
2813 	odbc_result	*result;
2814 	char    	tmp[32];
2815 	SQLSMALLINT	tmplen;
2816 	zval		*pv_res;
2817 	long		pv_num;
2818 
2819 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
2820 		return;
2821 	}
2822 
2823 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2824 
2825 	if (result->numcols == 0) {
2826 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2827 		RETURN_FALSE;
2828 	}
2829 
2830 	if (pv_num > result->numcols) {
2831 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
2832 		RETURN_FALSE;
2833 	}
2834 
2835 	if (pv_num < 1) {
2836 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
2837 		RETURN_FALSE;
2838 	}
2839 
2840 	SQLColAttributes(result->stmt, (SQLUSMALLINT)pv_num, SQL_COLUMN_TYPE_NAME, tmp, 31, &tmplen, NULL);
2841 	RETURN_STRING(tmp,1)
2842 }
2843 /* }}} */
2844 
2845 /* {{{ proto int odbc_field_len(resource result_id, int field_number)
2846    Get the length (precision) of a column */
PHP_FUNCTION(odbc_field_len)2847 PHP_FUNCTION(odbc_field_len)
2848 {
2849 	odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2850 }
2851 /* }}} */
2852 
2853 /* {{{ proto int odbc_field_scale(resource result_id, int field_number)
2854    Get the scale of a column */
PHP_FUNCTION(odbc_field_scale)2855 PHP_FUNCTION(odbc_field_scale)
2856 {
2857 	odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2858 }
2859 /* }}} */
2860 
2861 /* {{{ proto int odbc_field_num(resource result_id, string field_name)
2862    Return column number */
PHP_FUNCTION(odbc_field_num)2863 PHP_FUNCTION(odbc_field_num)
2864 {
2865 	char *fname;
2866 	int i, field_ind, fname_len;
2867 	odbc_result *result;
2868 	zval *pv_res;
2869 
2870 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_res, &fname, &fname_len) == FAILURE) {
2871 		return;
2872 	}
2873 
2874 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2875 
2876 	if (result->numcols == 0) {
2877 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2878 		RETURN_FALSE;
2879 	}
2880 
2881 	field_ind = -1;
2882 	for(i = 0; i < result->numcols; i++) {
2883 		if (strcasecmp(result->values[i].name, fname) == 0) {
2884 			field_ind = i + 1;
2885 		}
2886 	}
2887 
2888 	if (field_ind == -1) {
2889 		RETURN_FALSE;
2890 	}
2891 	RETURN_LONG(field_ind);
2892 }
2893 /* }}} */
2894 
2895 /* {{{ proto mixed odbc_autocommit(resource connection_id [, int OnOff])
2896    Toggle autocommit mode or get status */
2897 /* There can be problems with pconnections!*/
PHP_FUNCTION(odbc_autocommit)2898 PHP_FUNCTION(odbc_autocommit)
2899 {
2900 	odbc_connection *conn;
2901 	RETCODE rc;
2902 	zval *pv_conn;
2903 	long pv_onoff = 0;
2904 
2905 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_onoff) == FAILURE) {
2906 		return;
2907 	}
2908 
2909 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
2910 
2911 	if (ZEND_NUM_ARGS() > 1) {
2912 		rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (pv_onoff) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
2913 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2914 			odbc_sql_error(conn, SQL_NULL_HSTMT, "Set autocommit");
2915 			RETURN_FALSE;
2916 		}
2917 		RETVAL_TRUE;
2918 	} else {
2919 		SQLINTEGER status;
2920 
2921 		rc = SQLGetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (PTR)&status);
2922 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2923 			odbc_sql_error(conn, SQL_NULL_HSTMT, "Get commit status");
2924 			RETURN_FALSE;
2925 		}
2926 		RETVAL_LONG((long)status);
2927 	}
2928 }
2929 /* }}} */
2930 
2931 /* {{{ proto bool odbc_commit(resource connection_id)
2932    Commit an ODBC transaction */
PHP_FUNCTION(odbc_commit)2933 PHP_FUNCTION(odbc_commit)
2934 {
2935 	odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2936 }
2937 /* }}} */
2938 
2939 /* {{{ proto bool odbc_rollback(resource connection_id)
2940    Rollback a transaction */
PHP_FUNCTION(odbc_rollback)2941 PHP_FUNCTION(odbc_rollback)
2942 {
2943 	odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2944 }
2945 /* }}} */
2946 
2947 /* {{{ php_odbc_lasterror */
php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS,int mode)2948 static void php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS, int mode)
2949 {
2950 	odbc_connection *conn;
2951 	zval *pv_handle;
2952 	char *ptr;
2953 	int len;
2954 
2955 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &pv_handle) == FAILURE) {
2956 		return;
2957 	}
2958 
2959 	if (mode == 0) {  /* last state */
2960 		len = 6;
2961 	} else { /* last error message */
2962 		len = SQL_MAX_MESSAGE_LENGTH;
2963 	}
2964 
2965 	if (ZEND_NUM_ARGS() == 1) {
2966 		ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
2967 		ptr = ecalloc(len + 1, 1);
2968 		if (mode == 0) {
2969 			strlcpy(ptr, conn->laststate, len+1);
2970 		} else {
2971 			strlcpy(ptr, conn->lasterrormsg, len+1);
2972 		}
2973 	} else {
2974 		ptr = ecalloc(len + 1, 1);
2975 		if (mode == 0) {
2976 			strlcpy(ptr, ODBCG(laststate), len+1);
2977 		} else {
2978 			strlcpy(ptr, ODBCG(lasterrormsg), len+1);
2979 		}
2980 	}
2981 	RETVAL_STRING(ptr, 0);
2982 }
2983 /* }}} */
2984 
2985 /* {{{ proto string odbc_error([resource connection_id])
2986    Get the last error code */
PHP_FUNCTION(odbc_error)2987 PHP_FUNCTION(odbc_error)
2988 {
2989 	php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2990 }
2991 /* }}} */
2992 
2993 /* {{{ proto string odbc_errormsg([resource connection_id])
2994    Get the last error message */
PHP_FUNCTION(odbc_errormsg)2995 PHP_FUNCTION(odbc_errormsg)
2996 {
2997 	php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2998 }
2999 /* }}} */
3000 
3001 /* {{{ proto bool odbc_setoption(resource conn_id|result_id, int which, int option, int value)
3002    Sets connection or statement options */
3003 /* This one has to be used carefully. We can't allow to set connection options for
3004    persistent connections. I think that SetStmtOption is of little use, since most
3005    of those can only be specified before preparing/executing statements.
3006    On the other hand, they can be made connection wide default through SetConnectOption
3007    - but will be overidden by calls to SetStmtOption() in odbc_prepare/odbc_do
3008 */
PHP_FUNCTION(odbc_setoption)3009 PHP_FUNCTION(odbc_setoption)
3010 {
3011 	odbc_connection *conn;
3012 	odbc_result	*result;
3013 	RETCODE rc;
3014 	zval *pv_handle;
3015 	long pv_which, pv_opt, pv_val;
3016 
3017 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) {
3018 		return;
3019 	}
3020 
3021 	switch (pv_which) {
3022 		case 1:		/* SQLSetConnectOption */
3023 			ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
3024 
3025 			if (conn->persistent) {
3026 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set option for persistent connection");
3027 				RETURN_FALSE;
3028 			}
3029 			rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val);
3030 			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
3031 				odbc_sql_error(conn, SQL_NULL_HSTMT, "SetConnectOption");
3032 				RETURN_FALSE;
3033 			}
3034 			break;
3035 		case 2:		/* SQLSetStmtOption */
3036 			ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_handle, -1, "ODBC result", le_result);
3037 
3038 			rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val);
3039 
3040 			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
3041 				odbc_sql_error(result->conn_ptr, result->stmt, "SetStmtOption");
3042 				RETURN_FALSE;
3043 			}
3044 			break;
3045 		default:
3046 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option type");
3047 			RETURN_FALSE;
3048 			break;
3049 	}
3050 
3051 	RETURN_TRUE;
3052 }
3053 /* }}} */
3054 
3055 /*
3056  * metadata functions
3057  */
3058 
3059 /* {{{ proto resource odbc_tables(resource connection_id [, string qualifier [, string owner [, string name [, string table_types]]]])
3060    Call the SQLTables function */
PHP_FUNCTION(odbc_tables)3061 PHP_FUNCTION(odbc_tables)
3062 {
3063 	zval *pv_conn;
3064 	odbc_result   *result = NULL;
3065 	odbc_connection *conn;
3066 	char *cat = NULL, *schema = NULL, *table = NULL, *type = NULL;
3067 	int cat_len = 0, schema_len = 0, table_len = 0, type_len = 0;
3068 	RETCODE rc;
3069 
3070 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3071 		&table, &table_len, &type, &type_len) == FAILURE) {
3072 		return;
3073 	}
3074 
3075 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3076 
3077 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3078 
3079 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3080 	if (rc == SQL_INVALID_HANDLE) {
3081 		efree(result);
3082 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3083 		RETURN_FALSE;
3084 	}
3085 
3086 	if (rc == SQL_ERROR) {
3087 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3088 		efree(result);
3089 		RETURN_FALSE;
3090 	}
3091 
3092 	/* This hack is needed to access table information in Access databases (fmk) */
3093 	if (table && table_len && schema && schema_len == 0) {
3094 		schema = NULL;
3095 	}
3096 
3097 	rc = SQLTables(result->stmt,
3098 			cat, SAFE_SQL_NTS(cat),
3099 			schema,	SAFE_SQL_NTS(schema),
3100 			table, SAFE_SQL_NTS(table),
3101 			type, SAFE_SQL_NTS(type));
3102 
3103 	if (rc == SQL_ERROR) {
3104 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTables");
3105 		efree(result);
3106 		RETURN_FALSE;
3107 	}
3108 
3109 	result->numparams = 0;
3110 	SQLNumResultCols(result->stmt, &(result->numcols));
3111 
3112 	if (result->numcols > 0) {
3113 		if (!odbc_bindcols(result TSRMLS_CC)) {
3114 			efree(result);
3115 			RETURN_FALSE;
3116 		}
3117 	} else {
3118 		result->values = NULL;
3119 	}
3120 	result->conn_ptr = conn;
3121 	result->fetched = 0;
3122 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3123 }
3124 /* }}} */
3125 
3126 /* {{{ proto resource odbc_columns(resource connection_id [, string qualifier [, string owner [, string table_name [, string column_name]]]])
3127    Returns a result identifier that can be used to fetch a list of column names in specified tables */
PHP_FUNCTION(odbc_columns)3128 PHP_FUNCTION(odbc_columns)
3129 {
3130 	zval *pv_conn;
3131 	odbc_result *result = NULL;
3132 	odbc_connection *conn;
3133 	char *cat = NULL, *schema = NULL, *table = NULL, *column = NULL;
3134 	int cat_len = 0, schema_len = 0, table_len = 0, column_len = 0;
3135 	RETCODE rc;
3136 
3137 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3138 		&table, &table_len, &column, &column_len) == FAILURE) {
3139 		return;
3140 	}
3141 
3142 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3143 
3144 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3145 
3146 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3147 	if (rc == SQL_INVALID_HANDLE) {
3148 		efree(result);
3149 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3150 		RETURN_FALSE;
3151 	}
3152 
3153 	if (rc == SQL_ERROR) {
3154 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3155 		efree(result);
3156 		RETURN_FALSE;
3157 	}
3158 
3159 	/*
3160 	 * Needed to make MS Access happy
3161 	 */
3162 	if (table && table_len && schema && schema_len == 0) {
3163 		schema = NULL;
3164 	}
3165 
3166 	rc = SQLColumns(result->stmt,
3167 			cat, (SQLSMALLINT) cat_len,
3168 			schema, (SQLSMALLINT) schema_len,
3169 			table, (SQLSMALLINT) table_len,
3170 			column, (SQLSMALLINT) column_len);
3171 
3172 	if (rc == SQL_ERROR) {
3173 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumns");
3174 		efree(result);
3175 		RETURN_FALSE;
3176 	}
3177 
3178 	result->numparams = 0;
3179 	SQLNumResultCols(result->stmt, &(result->numcols));
3180 
3181 	if (result->numcols > 0) {
3182 		if (!odbc_bindcols(result TSRMLS_CC)) {
3183 			efree(result);
3184 			RETURN_FALSE;
3185 		}
3186 	} else {
3187 		result->values = NULL;
3188 	}
3189 	result->conn_ptr = conn;
3190 	result->fetched = 0;
3191 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3192 }
3193 /* }}} */
3194 
3195 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3196 /* {{{ proto resource odbc_columnprivileges(resource connection_id, string catalog, string schema, string table, string column)
3197    Returns a result identifier that can be used to fetch a list of columns and associated privileges for the specified table */
PHP_FUNCTION(odbc_columnprivileges)3198 PHP_FUNCTION(odbc_columnprivileges)
3199 {
3200 	zval *pv_conn;
3201 	odbc_result *result = NULL;
3202 	odbc_connection *conn;
3203 	char *cat = NULL, *schema, *table, *column;
3204 	int cat_len = 0, schema_len, table_len, column_len;
3205 	RETCODE rc;
3206 
3207 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3208 		&table, &table_len, &column, &column_len) == FAILURE) {
3209 		return;
3210 	}
3211 
3212 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3213 
3214 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3215 
3216 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3217 	if (rc == SQL_INVALID_HANDLE) {
3218 		efree(result);
3219 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3220 		RETURN_FALSE;
3221 	}
3222 
3223 	if (rc == SQL_ERROR) {
3224 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3225 		efree(result);
3226 		RETURN_FALSE;
3227 	}
3228 
3229 	rc = SQLColumnPrivileges(result->stmt,
3230 			cat, SAFE_SQL_NTS(cat),
3231 			schema, SAFE_SQL_NTS(schema),
3232 			table, SAFE_SQL_NTS(table),
3233 			column, SAFE_SQL_NTS(column));
3234 
3235 	if (rc == SQL_ERROR) {
3236 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumnPrivileges");
3237 		efree(result);
3238 		RETURN_FALSE;
3239 	}
3240 
3241 	result->numparams = 0;
3242 	SQLNumResultCols(result->stmt, &(result->numcols));
3243 
3244 	if (result->numcols > 0) {
3245 		if (!odbc_bindcols(result TSRMLS_CC)) {
3246 			efree(result);
3247 			RETURN_FALSE;
3248 		}
3249 	} else {
3250 		result->values = NULL;
3251 	}
3252 	result->conn_ptr = conn;
3253 	result->fetched = 0;
3254 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3255 }
3256 /* }}} */
3257 #endif /* HAVE_DBMAKER || HAVE_SOLID*/
3258 
3259 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
3260 /* {{{ proto resource odbc_foreignkeys(resource connection_id, string pk_qualifier, string pk_owner, string pk_table, string fk_qualifier, string fk_owner, string fk_table)
3261    Returns a result identifier to either a list of foreign keys in the specified table or a list of foreign keys in other tables that refer to the primary key in the specified table */
PHP_FUNCTION(odbc_foreignkeys)3262 PHP_FUNCTION(odbc_foreignkeys)
3263 {
3264 	zval *pv_conn;
3265 	odbc_result *result = NULL;
3266 	odbc_connection *conn;
3267 	char *pcat = NULL, *pschema, *ptable, *fcat, *fschema, *ftable;
3268 	int pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len;
3269 	RETCODE rc;
3270 
3271 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sssss", &pv_conn, &pcat, &pcat_len, &pschema, &pschema_len,
3272 		&ptable, &ptable_len, &fcat, &fcat_len, &fschema, &fschema_len, &ftable, &ftable_len) == FAILURE) {
3273 		return;
3274 	}
3275 
3276 #if defined(HAVE_DBMAKER) || defined(HAVE_IBMDB2)
3277 #define EMPTY_TO_NULL(xstr) \
3278 	if ((int)strlen((xstr)) == 0) (xstr) = NULL
3279 
3280 		EMPTY_TO_NULL(pcat);
3281 		EMPTY_TO_NULL(pschema);
3282 		EMPTY_TO_NULL(ptable);
3283 		EMPTY_TO_NULL(fcat);
3284 		EMPTY_TO_NULL(fschema);
3285 		EMPTY_TO_NULL(ftable);
3286 #endif
3287 
3288 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3289 
3290 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3291 
3292 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3293 	if (rc == SQL_INVALID_HANDLE) {
3294 		efree(result);
3295 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3296 		RETURN_FALSE;
3297 	}
3298 
3299 	if (rc == SQL_ERROR) {
3300 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3301 		efree(result);
3302 		RETURN_FALSE;
3303 	}
3304 
3305 	rc = SQLForeignKeys(result->stmt,
3306 			pcat, SAFE_SQL_NTS(pcat),
3307 			pschema, SAFE_SQL_NTS(pschema),
3308 			ptable, SAFE_SQL_NTS(ptable),
3309 			fcat, SAFE_SQL_NTS(fcat),
3310 			fschema, SAFE_SQL_NTS(fschema),
3311 			ftable, SAFE_SQL_NTS(ftable) );
3312 
3313 	if (rc == SQL_ERROR) {
3314 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLForeignKeys");
3315 		efree(result);
3316 		RETURN_FALSE;
3317 	}
3318 
3319 	result->numparams = 0;
3320 	SQLNumResultCols(result->stmt, &(result->numcols));
3321 
3322 	if (result->numcols > 0) {
3323 		if (!odbc_bindcols(result TSRMLS_CC)) {
3324 			efree(result);
3325 			RETURN_FALSE;
3326 		}
3327 	} else {
3328 		result->values = NULL;
3329 	}
3330 	result->conn_ptr = conn;
3331 	result->fetched = 0;
3332 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3333 }
3334 /* }}} */
3335 #endif /* HAVE_SOLID */
3336 
3337 /* {{{ proto resource odbc_gettypeinfo(resource connection_id [, int data_type])
3338    Returns a result identifier containing information about data types supported by the data source */
PHP_FUNCTION(odbc_gettypeinfo)3339 PHP_FUNCTION(odbc_gettypeinfo)
3340 {
3341 	zval *pv_conn;
3342 	long pv_data_type = SQL_ALL_TYPES;
3343 	odbc_result *result = NULL;
3344 	odbc_connection *conn;
3345 	RETCODE rc;
3346 	SQLSMALLINT data_type;
3347 
3348 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_data_type) == FAILURE) {
3349 		return;
3350 	}
3351 
3352 	data_type = (SQLSMALLINT) pv_data_type;
3353 
3354 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3355 
3356 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3357 
3358 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3359 	if (rc == SQL_INVALID_HANDLE) {
3360 		efree(result);
3361 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3362 		RETURN_FALSE;
3363 	}
3364 
3365 	if (rc == SQL_ERROR) {
3366 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3367 		efree(result);
3368 		RETURN_FALSE;
3369 	}
3370 
3371 	rc = SQLGetTypeInfo(result->stmt, data_type );
3372 
3373 	if (rc == SQL_ERROR) {
3374 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLGetTypeInfo");
3375 		efree(result);
3376 		RETURN_FALSE;
3377 	}
3378 
3379 	result->numparams = 0;
3380 	SQLNumResultCols(result->stmt, &(result->numcols));
3381 
3382 	if (result->numcols > 0) {
3383 		if (!odbc_bindcols(result TSRMLS_CC)) {
3384 			efree(result);
3385 			RETURN_FALSE;
3386 		}
3387 	} else {
3388 		result->values = NULL;
3389 	}
3390 	result->conn_ptr = conn;
3391 	result->fetched = 0;
3392 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3393 }
3394 /* }}} */
3395 
3396 /* {{{ proto resource odbc_primarykeys(resource connection_id, string qualifier, string owner, string table)
3397    Returns a result identifier listing the column names that comprise the primary key for a table */
PHP_FUNCTION(odbc_primarykeys)3398 PHP_FUNCTION(odbc_primarykeys)
3399 {
3400 	zval *pv_conn;
3401 	odbc_result   *result = NULL;
3402 	odbc_connection *conn;
3403 	char *cat = NULL, *schema = NULL, *table = NULL;
3404 	int cat_len = 0, schema_len, table_len;
3405 	RETCODE rc;
3406 
3407 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
3408 		return;
3409 	}
3410 
3411 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3412 
3413 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3414 
3415 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3416 	if (rc == SQL_INVALID_HANDLE) {
3417 		efree(result);
3418 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3419 		RETURN_FALSE;
3420 	}
3421 
3422 	if (rc == SQL_ERROR) {
3423 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3424 		efree(result);
3425 		RETURN_FALSE;
3426 	}
3427 
3428 	rc = SQLPrimaryKeys(result->stmt,
3429 			cat, SAFE_SQL_NTS(cat),
3430 			schema, SAFE_SQL_NTS(schema),
3431 			table, SAFE_SQL_NTS(table) );
3432 
3433 	if (rc == SQL_ERROR) {
3434 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLPrimaryKeys");
3435 		efree(result);
3436 		RETURN_FALSE;
3437 	}
3438 
3439 	result->numparams = 0;
3440 	SQLNumResultCols(result->stmt, &(result->numcols));
3441 
3442 	if (result->numcols > 0) {
3443 		if (!odbc_bindcols(result TSRMLS_CC)) {
3444 			efree(result);
3445 			RETURN_FALSE;
3446 		}
3447 	} else {
3448 		result->values = NULL;
3449 	}
3450 	result->conn_ptr = conn;
3451 	result->fetched = 0;
3452 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3453 }
3454 /* }}} */
3455 
3456 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3457 /* {{{ proto resource odbc_procedurecolumns(resource connection_id [, string qualifier, string owner, string proc, string column])
3458    Returns a result identifier containing the list of input and output parameters, as well as the columns that make up the result set for the specified procedures */
PHP_FUNCTION(odbc_procedurecolumns)3459 PHP_FUNCTION(odbc_procedurecolumns)
3460 {
3461 	zval *pv_conn;
3462 	odbc_result *result = NULL;
3463 	odbc_connection *conn;
3464 	char *cat = NULL, *schema = NULL, *proc = NULL, *col = NULL;
3465 	int cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0;
3466 	RETCODE rc;
3467 
3468 	if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 5) {
3469 		WRONG_PARAM_COUNT;
3470 	}
3471 
3472 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3473 		&proc, &proc_len, &col, &col_len) == FAILURE) {
3474 		return;
3475 	}
3476 
3477 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3478 
3479 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3480 
3481 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3482 	if (rc == SQL_INVALID_HANDLE) {
3483 		efree(result);
3484 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3485 		RETURN_FALSE;
3486 	}
3487 
3488 	if (rc == SQL_ERROR) {
3489 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3490 		efree(result);
3491 		RETURN_FALSE;
3492 	}
3493 
3494 	rc = SQLProcedureColumns(result->stmt,
3495 			cat, SAFE_SQL_NTS(cat),
3496 			schema, SAFE_SQL_NTS(schema),
3497 			proc, SAFE_SQL_NTS(proc),
3498 			col, SAFE_SQL_NTS(col) );
3499 
3500 	if (rc == SQL_ERROR) {
3501 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedureColumns");
3502 		efree(result);
3503 		RETURN_FALSE;
3504 	}
3505 
3506 	result->numparams = 0;
3507 	SQLNumResultCols(result->stmt, &(result->numcols));
3508 
3509 	if (result->numcols > 0) {
3510 		if (!odbc_bindcols(result TSRMLS_CC)) {
3511 			efree(result);
3512 			RETURN_FALSE;
3513 		}
3514 	} else {
3515 		result->values = NULL;
3516 	}
3517 	result->conn_ptr = conn;
3518 	result->fetched = 0;
3519 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3520 }
3521 /* }}} */
3522 #endif /* HAVE_SOLID */
3523 
3524 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
3525 /* {{{ proto resource odbc_procedures(resource connection_id [, string qualifier, string owner, string name])
3526    Returns a result identifier containg the list of procedure names in a datasource */
PHP_FUNCTION(odbc_procedures)3527 PHP_FUNCTION(odbc_procedures)
3528 {
3529 	zval *pv_conn;
3530 	odbc_result   *result = NULL;
3531 	odbc_connection *conn;
3532 	char *cat = NULL, *schema = NULL, *proc = NULL;
3533 	int cat_len = 0, schema_len = 0, proc_len = 0;
3534 	RETCODE rc;
3535 
3536 	if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 4) {
3537 		WRONG_PARAM_COUNT;
3538 	}
3539 
3540 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) {
3541 		return;
3542 	}
3543 
3544 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3545 
3546 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3547 
3548 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3549 	if (rc == SQL_INVALID_HANDLE) {
3550 		efree(result);
3551 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3552 		RETURN_FALSE;
3553 	}
3554 
3555 	if (rc == SQL_ERROR) {
3556 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3557 		efree(result);
3558 		RETURN_FALSE;
3559 	}
3560 
3561 	rc = SQLProcedures(result->stmt,
3562 			cat, SAFE_SQL_NTS(cat),
3563 			schema, SAFE_SQL_NTS(schema),
3564 			proc, SAFE_SQL_NTS(proc) );
3565 
3566 	if (rc == SQL_ERROR) {
3567 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedures");
3568 		efree(result);
3569 		RETURN_FALSE;
3570 	}
3571 
3572 	result->numparams = 0;
3573 	SQLNumResultCols(result->stmt, &(result->numcols));
3574 
3575 	if (result->numcols > 0) {
3576 		if (!odbc_bindcols(result TSRMLS_CC)) {
3577 			efree(result);
3578 			RETURN_FALSE;
3579 		}
3580 	} else {
3581 		result->values = NULL;
3582 	}
3583 	result->conn_ptr = conn;
3584 	result->fetched = 0;
3585 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3586 }
3587 /* }}} */
3588 #endif /* HAVE_SOLID */
3589 
3590 /* {{{ proto resource odbc_specialcolumns(resource connection_id, int type, string qualifier, string owner, string table, int scope, int nullable)
3591    Returns a result identifier containing either the optimal set of columns that uniquely identifies a row in the table or columns that are automatically updated when any value in the row is updated by a transaction */
PHP_FUNCTION(odbc_specialcolumns)3592 PHP_FUNCTION(odbc_specialcolumns)
3593 {
3594 	zval *pv_conn;
3595 	long vtype, vscope, vnullable;
3596 	odbc_result *result = NULL;
3597 	odbc_connection *conn;
3598 	char *cat = NULL, *schema = NULL, *name = NULL;
3599 	int cat_len = 0, schema_len, name_len;
3600 	SQLUSMALLINT type, scope, nullable;
3601 	RETCODE rc;
3602 
3603 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rls!ssll", &pv_conn, &vtype, &cat, &cat_len, &schema, &schema_len,
3604 		&name, &name_len, &vscope, &vnullable) == FAILURE) {
3605 		return;
3606 	}
3607 
3608 	type = (SQLUSMALLINT) vtype;
3609 	scope = (SQLUSMALLINT) vscope;
3610 	nullable = (SQLUSMALLINT) vnullable;
3611 
3612 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3613 
3614 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3615 
3616 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3617 	if (rc == SQL_INVALID_HANDLE) {
3618 		efree(result);
3619 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3620 		RETURN_FALSE;
3621 	}
3622 
3623 	if (rc == SQL_ERROR) {
3624 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3625 		efree(result);
3626 		RETURN_FALSE;
3627 	}
3628 
3629 	rc = SQLSpecialColumns(result->stmt,
3630 			type,
3631 			cat, SAFE_SQL_NTS(cat),
3632 			schema, SAFE_SQL_NTS(schema),
3633 			name, SAFE_SQL_NTS(name),
3634 			scope,
3635 			nullable);
3636 
3637 	if (rc == SQL_ERROR) {
3638 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLSpecialColumns");
3639 		efree(result);
3640 		RETURN_FALSE;
3641 	}
3642 
3643 	result->numparams = 0;
3644 	SQLNumResultCols(result->stmt, &(result->numcols));
3645 
3646 	if (result->numcols > 0) {
3647 		if (!odbc_bindcols(result TSRMLS_CC)) {
3648 			efree(result);
3649 			RETURN_FALSE;
3650 		}
3651 	} else {
3652 		result->values = NULL;
3653 	}
3654 	result->conn_ptr = conn;
3655 	result->fetched = 0;
3656 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3657 }
3658 /* }}} */
3659 
3660 /* {{{ proto resource odbc_statistics(resource connection_id, string qualifier, string owner, string name, int unique, int accuracy)
3661    Returns a result identifier that contains statistics about a single table and the indexes associated with the table */
PHP_FUNCTION(odbc_statistics)3662 PHP_FUNCTION(odbc_statistics)
3663 {
3664 	zval *pv_conn;
3665 	long vunique, vreserved;
3666 	odbc_result *result = NULL;
3667 	odbc_connection *conn;
3668 	char *cat = NULL, *schema, *name;
3669 	int cat_len = 0, schema_len, name_len;
3670 	SQLUSMALLINT unique, reserved;
3671 	RETCODE rc;
3672 
3673 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ssll", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3674 		&name, &name_len, &vunique, &vreserved) == FAILURE) {
3675 		return;
3676 	}
3677 
3678 	unique = (SQLUSMALLINT) vunique;
3679 	reserved = (SQLUSMALLINT) vreserved;
3680 
3681 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3682 
3683 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3684 
3685 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3686 	if (rc == SQL_INVALID_HANDLE) {
3687 		efree(result);
3688 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3689 		RETURN_FALSE;
3690 	}
3691 
3692 	if (rc == SQL_ERROR) {
3693 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3694 		efree(result);
3695 		RETURN_FALSE;
3696 	}
3697 
3698 	rc = SQLStatistics(result->stmt,
3699 			cat, SAFE_SQL_NTS(cat),
3700 			schema, SAFE_SQL_NTS(schema),
3701 			name, SAFE_SQL_NTS(name),
3702 			unique,
3703 			reserved);
3704 
3705 	if (rc == SQL_ERROR) {
3706 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLStatistics");
3707 		efree(result);
3708 		RETURN_FALSE;
3709 	}
3710 
3711 	result->numparams = 0;
3712 	SQLNumResultCols(result->stmt, &(result->numcols));
3713 
3714 	if (result->numcols > 0) {
3715 		if (!odbc_bindcols(result TSRMLS_CC)) {
3716 			efree(result);
3717 			RETURN_FALSE;
3718 		}
3719 	} else {
3720 		result->values = NULL;
3721 	}
3722 	result->conn_ptr = conn;
3723 	result->fetched = 0;
3724 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3725 }
3726 /* }}} */
3727 
3728 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3729 /* {{{ proto resource odbc_tableprivileges(resource connection_id, string qualifier, string owner, string name)
3730    Returns a result identifier containing a list of tables and the privileges associated with each table */
PHP_FUNCTION(odbc_tableprivileges)3731 PHP_FUNCTION(odbc_tableprivileges)
3732 {
3733 	zval *pv_conn;
3734 	odbc_result   *result = NULL;
3735 	odbc_connection *conn;
3736 	char *cat = NULL, *schema = NULL, *table = NULL;
3737 	int cat_len = 0, schema_len, table_len;
3738 	RETCODE rc;
3739 
3740 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
3741 		return;
3742 	}
3743 
3744 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3745 
3746 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3747 
3748 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3749 	if (rc == SQL_INVALID_HANDLE) {
3750 		efree(result);
3751 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3752 		RETURN_FALSE;
3753 	}
3754 
3755 	if (rc == SQL_ERROR) {
3756 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3757 		efree(result);
3758 		RETURN_FALSE;
3759 	}
3760 
3761 	rc = SQLTablePrivileges(result->stmt,
3762 			cat, SAFE_SQL_NTS(cat),
3763 			schema, SAFE_SQL_NTS(schema),
3764 			table, SAFE_SQL_NTS(table));
3765 
3766 	if (rc == SQL_ERROR) {
3767 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTablePrivileges");
3768 		efree(result);
3769 		RETURN_FALSE;
3770 	}
3771 
3772 	result->numparams = 0;
3773 	SQLNumResultCols(result->stmt, &(result->numcols));
3774 
3775 	if (result->numcols > 0) {
3776 		if (!odbc_bindcols(result TSRMLS_CC)) {
3777 			efree(result);
3778 			RETURN_FALSE;
3779 		}
3780 	} else {
3781 		result->values = NULL;
3782 	}
3783 	result->conn_ptr = conn;
3784 	result->fetched = 0;
3785 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3786 }
3787 /* }}} */
3788 #endif /* HAVE_DBMAKER */
3789 
3790 #endif /* HAVE_UODBC */
3791 
3792 /*
3793  * Local variables:
3794  * tab-width: 4
3795  * c-basic-offset: 4
3796  * End:
3797  * vim600: sw=4 ts=4 fdm=marker
3798  * vim<600: sw=4 ts=4
3799  */
3800