xref: /PHP-5.4/ext/odbc/php_odbc.c (revision 65364fe7)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 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 	REGISTER_LONG_CONSTANT("SQL_WCHAR", SQL_WCHAR, CONST_PERSISTENT | CONST_CS);
784 	REGISTER_LONG_CONSTANT("SQL_WVARCHAR", SQL_WVARCHAR, CONST_PERSISTENT | CONST_CS);
785 	REGISTER_LONG_CONSTANT("SQL_WLONGVARCHAR", SQL_WLONGVARCHAR, CONST_PERSISTENT | CONST_CS);
786 
787 	/*
788 	 * SQLSpecialColumns values
789 	 */
790 	REGISTER_LONG_CONSTANT("SQL_BEST_ROWID", SQL_BEST_ROWID, CONST_PERSISTENT | CONST_CS);
791 	REGISTER_LONG_CONSTANT("SQL_ROWVER", SQL_ROWVER, CONST_PERSISTENT | CONST_CS);
792 	REGISTER_LONG_CONSTANT("SQL_SCOPE_CURROW", SQL_SCOPE_CURROW, CONST_PERSISTENT | CONST_CS);
793 	REGISTER_LONG_CONSTANT("SQL_SCOPE_TRANSACTION", SQL_SCOPE_TRANSACTION, CONST_PERSISTENT | CONST_CS);
794 	REGISTER_LONG_CONSTANT("SQL_SCOPE_SESSION", SQL_SCOPE_SESSION, CONST_PERSISTENT | CONST_CS);
795 	REGISTER_LONG_CONSTANT("SQL_NO_NULLS", SQL_NO_NULLS, CONST_PERSISTENT | CONST_CS);
796 	REGISTER_LONG_CONSTANT("SQL_NULLABLE", SQL_NULLABLE, CONST_PERSISTENT | CONST_CS);
797 
798 	/*
799 	 * SQLStatistics values
800 	 */
801 	REGISTER_LONG_CONSTANT("SQL_INDEX_UNIQUE", SQL_INDEX_UNIQUE, CONST_PERSISTENT | CONST_CS);
802 	REGISTER_LONG_CONSTANT("SQL_INDEX_ALL", SQL_INDEX_ALL, CONST_PERSISTENT | CONST_CS);
803 	REGISTER_LONG_CONSTANT("SQL_ENSURE", SQL_ENSURE, CONST_PERSISTENT | CONST_CS);
804 	REGISTER_LONG_CONSTANT("SQL_QUICK", SQL_QUICK, CONST_PERSISTENT | CONST_CS);
805 #endif
806 
807 #if defined(HAVE_IBMDB2) && defined(_AIX)
808 	/* atexit() handler in the DB2/AIX library segfaults in PHP CLI */
809 	/* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */
810 	putenv("DB2NOEXITLIST=TRUE");
811 #endif
812 
813 	return SUCCESS;
814 }
815 /* }}} */
816 
817 /* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(odbc)818 PHP_RINIT_FUNCTION(odbc)
819 {
820 	ODBCG(defConn) = -1;
821 	ODBCG(num_links) = ODBCG(num_persistent);
822 	memset(ODBCG(laststate), '\0', 6);
823 	memset(ODBCG(lasterrormsg), '\0', SQL_MAX_MESSAGE_LENGTH);
824 	return SUCCESS;
825 }
826 /* }}} */
827 
828 /* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(odbc)829 PHP_RSHUTDOWN_FUNCTION(odbc)
830 {
831 	return SUCCESS;
832 }
833 /* }}} */
834 
835 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(odbc)836 PHP_MSHUTDOWN_FUNCTION(odbc)
837 {
838 	UNREGISTER_INI_ENTRIES();
839 	return SUCCESS;
840 }
841 /* }}} */
842 
843 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(odbc)844 PHP_MINFO_FUNCTION(odbc)
845 {
846 	char buf[32];
847 
848 	php_info_print_table_start();
849 	php_info_print_table_header(2, "ODBC Support", "enabled");
850 	snprintf(buf, sizeof(buf), "%ld", ODBCG(num_persistent));
851 	php_info_print_table_row(2, "Active Persistent Links", buf);
852 	snprintf(buf, sizeof(buf), "%ld", ODBCG(num_links));
853 	php_info_print_table_row(2, "Active Links", buf);
854 	php_info_print_table_row(2, "ODBC library", PHP_ODBC_TYPE);
855 #ifndef PHP_WIN32
856 	php_info_print_table_row(2, "ODBC_INCLUDE", PHP_ODBC_INCLUDE);
857 	php_info_print_table_row(2, "ODBC_LFLAGS", PHP_ODBC_LFLAGS);
858 	php_info_print_table_row(2, "ODBC_LIBS", PHP_ODBC_LIBS);
859 #endif
860 	php_info_print_table_end();
861 
862 	DISPLAY_INI_ENTRIES();
863 
864 }
865 /* }}} */
866 
867 /* {{{ odbc_sql_error */
odbc_sql_error(ODBC_SQL_ERROR_PARAMS)868 void odbc_sql_error(ODBC_SQL_ERROR_PARAMS)
869 {
870 	char   	    state[6];
871 	SQLINTEGER	error;        /* Not used */
872 	char   	    errormsg[SQL_MAX_MESSAGE_LENGTH];
873 	SQLSMALLINT	errormsgsize; /* Not used */
874 	RETCODE rc;
875 	ODBC_SQL_ENV_T henv;
876 	ODBC_SQL_CONN_T conn;
877 	TSRMLS_FETCH();
878 
879 	if (conn_resource) {
880 		henv = conn_resource->henv;
881 		conn = conn_resource->hdbc;
882 	} else {
883 		henv = SQL_NULL_HENV;
884 		conn = SQL_NULL_HDBC;
885 	}
886 
887 	/* This leads to an endless loop in many drivers!
888 	 *
889 	   while(henv != SQL_NULL_HENV){
890 		do {
891 	 */
892 	rc = SQLError(henv, conn, stmt, state, &error, errormsg, sizeof(errormsg)-1, &errormsgsize);
893 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
894 		snprintf(state, sizeof(state), "HY000");
895 		snprintf(errormsg, sizeof(errormsg), "Failed to fetch error message");
896 	}
897 	if (conn_resource) {
898 		memcpy(conn_resource->laststate, state, sizeof(state));
899 		memcpy(conn_resource->lasterrormsg, errormsg, sizeof(errormsg));
900 	}
901 	memcpy(ODBCG(laststate), state, sizeof(state));
902 	memcpy(ODBCG(lasterrormsg), errormsg, sizeof(errormsg));
903 	if (func) {
904 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s in %s", errormsg, state, func);
905 	} else {
906 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
907 	}
908 	/*
909 		} while (SQL_SUCCEEDED(rc));
910 	}
911 	*/
912 }
913 /* }}} */
914 
915 /* {{{ php_odbc_fetch_attribs */
php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS,int mode)916 void php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS, int mode)
917 {
918 	odbc_result *result;
919 	zval *pv_res;
920 	long flag;
921 
922 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &flag) == FAILURE) {
923 		return;
924 	}
925 
926 	if (Z_LVAL_P(pv_res)) {
927 		ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
928         if (mode) {
929             result->longreadlen = flag;
930         } else {
931             result->binmode = flag;
932 		}
933 	} else {
934         if (mode) {
935             ODBCG(defaultlrl) = flag;
936         } else {
937             ODBCG(defaultbinmode) = flag;
938 		}
939 	}
940 	RETURN_TRUE;
941 }
942 /* }}} */
943 
944 /* {{{ odbc_bindcols */
odbc_bindcols(odbc_result * result TSRMLS_DC)945 int odbc_bindcols(odbc_result *result TSRMLS_DC)
946 {
947 	RETCODE rc;
948 	int i;
949 	SQLSMALLINT 	colnamelen; /* Not used */
950 	SQLLEN      	displaysize;
951 	SQLUSMALLINT	colfieldid;
952 	int		charextraalloc;
953 
954 	colfieldid = SQL_COLUMN_DISPLAY_SIZE;
955 	charextraalloc = 0;
956 	result->values = (odbc_result_value *) safe_emalloc(sizeof(odbc_result_value), result->numcols, 0);
957 
958 	result->longreadlen = ODBCG(defaultlrl);
959 	result->binmode = ODBCG(defaultbinmode);
960 
961 	for(i = 0; i < result->numcols; i++) {
962 		rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_NAME,
963 				result->values[i].name, sizeof(result->values[i].name), &colnamelen, 0);
964 		rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_TYPE,
965 				NULL, 0, NULL, &result->values[i].coltype);
966 
967 		/* Don't bind LONG / BINARY columns, so that fetch behaviour can
968 		 * be controlled by odbc_binmode() / odbc_longreadlen()
969 		 */
970 
971 		switch(result->values[i].coltype) {
972 			case SQL_BINARY:
973 			case SQL_VARBINARY:
974 			case SQL_LONGVARBINARY:
975 			case SQL_LONGVARCHAR:
976 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
977 			case SQL_WLONGVARCHAR:
978 #endif
979 				result->values[i].value = NULL;
980 				break;
981 
982 #ifdef HAVE_ADABAS
983 			case SQL_TIMESTAMP:
984 				result->values[i].value = (char *)emalloc(27);
985 				SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
986 							27, &result->values[i].vallen);
987 				break;
988 #endif /* HAVE_ADABAS */
989 			case SQL_CHAR:
990 			case SQL_VARCHAR:
991 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
992 			case SQL_WCHAR:
993 			case SQL_WVARCHAR:
994 				colfieldid = SQL_DESC_OCTET_LENGTH;
995 #else
996 				charextraalloc = 1;
997 #endif
998 			default:
999 				rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), colfieldid,
1000 								NULL, 0, NULL, &displaysize);
1001 				/* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */
1002 				if (result->values[i].coltype == SQL_TIMESTAMP) {
1003 					displaysize += 3;
1004 				}
1005 
1006 				if (charextraalloc) {
1007 					/* Since we don't know the exact # of bytes, allocate extra */
1008 					displaysize *= 4;
1009 				}
1010 				result->values[i].value = (char *)emalloc(displaysize + 1);
1011 				rc = SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
1012 							displaysize + 1, &result->values[i].vallen);
1013 				break;
1014 		}
1015 	}
1016 	return 1;
1017 }
1018 /* }}} */
1019 
1020 /* {{{ odbc_transact */
odbc_transact(INTERNAL_FUNCTION_PARAMETERS,int type)1021 void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type)
1022 {
1023 	odbc_connection *conn;
1024 	RETCODE rc;
1025 	zval *pv_conn;
1026 
1027 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
1028 		return;
1029 	}
1030 
1031 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1032 
1033 	rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK));
1034 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1035 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTransact");
1036 		RETURN_FALSE;
1037 	}
1038 
1039 	RETURN_TRUE;
1040 }
1041 /* }}} */
1042 
1043 /* {{{ _close_pconn_with_id */
_close_pconn_with_id(zend_rsrc_list_entry * le,int * id TSRMLS_DC)1044 static int _close_pconn_with_id(zend_rsrc_list_entry *le, int *id TSRMLS_DC)
1045 {
1046 	if(Z_TYPE_P(le) == le_pconn && (((odbc_connection *)(le->ptr))->id == *id)){
1047 		return 1;
1048 	}else{
1049 		return 0;
1050 	}
1051 }
1052 /* }}} */
1053 
1054 /* {{{ odbc_column_lengths */
odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS,int type)1055 void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
1056 {
1057 	odbc_result *result;
1058 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
1059 	/* this seems to be necessary for Solid2.3 ( tested by
1060 	 * tammy@synchronis.com) and Solid 3.0 (tested by eric@terra.telemediair.nl)
1061 	 * Solid does not seem to declare a SQLINTEGER, but it does declare a
1062 	 * SQL_INTEGER which does not work (despite being the same type as a SDWORD.
1063 	 * Solid 3.5 does not have this issue.
1064 	 */
1065 	SDWORD len;
1066 #else
1067 	SQLLEN len;
1068 #endif
1069 	zval *pv_res;
1070 	long pv_num;
1071 
1072 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
1073 		return;
1074 	}
1075 
1076 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1077 
1078 	if (result->numcols == 0) {
1079 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1080 		RETURN_FALSE;
1081 	}
1082 
1083 	if (pv_num > result->numcols) {
1084 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
1085 		RETURN_FALSE;
1086 	}
1087 
1088 	if (pv_num < 1) {
1089 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
1090 		RETURN_FALSE;
1091 	}
1092 
1093 	SQLColAttributes(result->stmt, (SQLUSMALLINT)pv_num, (SQLUSMALLINT) (type?SQL_COLUMN_SCALE:SQL_COLUMN_PRECISION), NULL, 0, NULL, &len);
1094 
1095 	RETURN_LONG(len);
1096 }
1097 /* }}} */
1098 
1099 /* Main User Functions */
1100 
1101 /* {{{ proto void odbc_close_all(void)
1102    Close all ODBC connections */
PHP_FUNCTION(odbc_close_all)1103 PHP_FUNCTION(odbc_close_all)
1104 {
1105 	void *ptr;
1106 	int type;
1107 	int i;
1108 	int nument;
1109 
1110 	if (zend_parse_parameters_none() == FAILURE) {
1111 		return;
1112 	}
1113 
1114 	nument = zend_hash_next_free_element(&EG(regular_list));
1115 
1116 	/* Loop through list and close all statements */
1117 	for(i = 1; i < nument; i++) {
1118 		ptr = zend_list_find(i, &type);
1119 		if (ptr && (type == le_result)){
1120 			zend_list_delete(i);
1121 		}
1122 	}
1123 
1124 	/* Second loop through list, now close all connections */
1125 	nument = zend_hash_next_free_element(&EG(regular_list));
1126 
1127 	for(i = 1; i < nument; i++) {
1128 		ptr = zend_list_find(i, &type);
1129 		if (ptr){
1130 			if(type == le_conn){
1131 				zend_list_delete(i);
1132 			}else if(type == le_pconn){
1133 				zend_list_delete(i);
1134 				/* Delete the persistent connection */
1135 				zend_hash_apply_with_argument(&EG(persistent_list),
1136 					(apply_func_arg_t) _close_pconn_with_id, (void *) &i TSRMLS_CC);
1137 			}
1138 		}
1139 	}
1140 }
1141 /* }}} */
1142 
1143 /* {{{ proto bool odbc_binmode(int result_id, int mode)
1144    Handle binary column data */
PHP_FUNCTION(odbc_binmode)1145 PHP_FUNCTION(odbc_binmode)
1146 {
1147 	php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1148 }
1149 /* }}} */
1150 
1151 /* {{{ proto bool odbc_longreadlen(int result_id, int length)
1152    Handle LONG columns */
PHP_FUNCTION(odbc_longreadlen)1153 PHP_FUNCTION(odbc_longreadlen)
1154 {
1155 	php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1156 }
1157 /* }}} */
1158 
1159 /* {{{ proto resource odbc_prepare(resource connection_id, string query)
1160    Prepares a statement for execution */
PHP_FUNCTION(odbc_prepare)1161 PHP_FUNCTION(odbc_prepare)
1162 {
1163 	zval *pv_conn;
1164 	char *query;
1165 	int query_len;
1166 	odbc_result *result = NULL;
1167 	odbc_connection *conn;
1168 	RETCODE rc;
1169 #ifdef HAVE_SQL_EXTENDED_FETCH
1170 	SQLUINTEGER      scrollopts;
1171 #endif
1172 
1173 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_conn, &query, &query_len) == FAILURE) {
1174 		return;
1175 	}
1176 
1177 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1178 
1179 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
1180 
1181 	result->numparams = 0;
1182 
1183 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
1184 	if (rc == SQL_INVALID_HANDLE) {
1185 		efree(result);
1186 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
1187 		RETURN_FALSE;
1188 	}
1189 
1190 	if (rc == SQL_ERROR) {
1191 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
1192 		efree(result);
1193 		RETURN_FALSE;
1194 	}
1195 
1196 #ifdef HAVE_SQL_EXTENDED_FETCH
1197 	/* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
1198 	   whether Driver supports ExtendedFetch */
1199 	rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
1200 	if (rc == SQL_SUCCESS) {
1201 		if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
1202 			/* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
1203 			   type if not possible.
1204 			*/
1205 			SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
1206 		}
1207 	} else {
1208 		result->fetch_abs = 0;
1209 	}
1210 #endif
1211 
1212 	rc = SQLPrepare(result->stmt, query, SQL_NTS);
1213 	switch (rc) {
1214 		case SQL_SUCCESS:
1215 			break;
1216 		case SQL_SUCCESS_WITH_INFO:
1217 			odbc_sql_error(conn, result->stmt, "SQLPrepare");
1218 			break;
1219 		default:
1220 			odbc_sql_error(conn, result->stmt, "SQLPrepare");
1221 			RETURN_FALSE;
1222 	}
1223 
1224 	SQLNumParams(result->stmt, &(result->numparams));
1225 	SQLNumResultCols(result->stmt, &(result->numcols));
1226 
1227 	if (result->numcols > 0) {
1228 		if (!odbc_bindcols(result TSRMLS_CC)) {
1229 			efree(result);
1230 			RETURN_FALSE;
1231 		}
1232 	} else {
1233 		result->values = NULL;
1234 	}
1235 	zend_list_addref(conn->id);
1236 	result->conn_ptr = conn;
1237 	result->fetched = 0;
1238 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1239 }
1240 /* }}} */
1241 
1242 /*
1243  * Execute prepared SQL statement. Supports only input parameters.
1244  */
1245 
1246 /* {{{ proto bool odbc_execute(resource result_id [, array parameters_array])
1247    Execute a prepared statement */
PHP_FUNCTION(odbc_execute)1248 PHP_FUNCTION(odbc_execute)
1249 {
1250 	zval *pv_res, *pv_param_arr, **tmp;
1251 	typedef struct params_t {
1252 		SQLLEN vallen;
1253 		int fp;
1254 	} params_t;
1255 	params_t *params = NULL;
1256 	char *filename;
1257 	unsigned char otype;
1258    	SQLSMALLINT sqltype, ctype, scale;
1259 	SQLSMALLINT nullable;
1260 	SQLULEN precision;
1261    	odbc_result *result;
1262 	int numArgs, i, ne;
1263 	RETCODE rc;
1264 
1265 	numArgs = ZEND_NUM_ARGS();
1266 
1267 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|a", &pv_res, &pv_param_arr) == FAILURE) {
1268 		return;
1269 	}
1270 
1271 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1272 
1273 	/* XXX check for already bound parameters*/
1274 	if (result->numparams > 0 && numArgs == 1) {
1275 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No parameters to SQL statement given");
1276 		RETURN_FALSE;
1277 	}
1278 
1279 	if (result->numparams > 0) {
1280 		if ((ne = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr))) < result->numparams) {
1281 			php_error_docref(NULL TSRMLS_CC, E_WARNING,"Not enough parameters (%d should be %d) given", ne, result->numparams);
1282 			RETURN_FALSE;
1283 		}
1284 
1285 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
1286 		params = (params_t *)safe_emalloc(sizeof(params_t), result->numparams, 0);
1287 		for(i = 0; i < result->numparams; i++) {
1288 			params[i].fp = -1;
1289 		}
1290 
1291 		for(i = 1; i <= result->numparams; i++) {
1292 			if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
1293 				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
1294 				SQLFreeStmt(result->stmt,SQL_RESET_PARAMS);
1295 				for (i = 0; i < result->numparams; i++) {
1296 					if (params[i].fp != -1) {
1297 						close(params[i].fp);
1298 					}
1299 				}
1300 				efree(params);
1301 				RETURN_FALSE;
1302 			}
1303 
1304 			otype = (*tmp)->type;
1305 			convert_to_string_ex(tmp);
1306 			if (Z_TYPE_PP(tmp) != IS_STRING) {
1307 				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
1308 				SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1309 				for (i = 0; i < result->numparams; i++) {
1310 					if (params[i].fp != -1) {
1311 						close(params[i].fp);
1312 					}
1313 				}
1314 				efree(params);
1315 				RETURN_FALSE;
1316 			}
1317 
1318 			rc = SQLDescribeParam(result->stmt, (SQLUSMALLINT)i, &sqltype, &precision, &scale, &nullable);
1319 			params[i-1].vallen = Z_STRLEN_PP(tmp);
1320 			params[i-1].fp = -1;
1321 			if (rc == SQL_ERROR) {
1322 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter");
1323 				SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1324 				for (i = 0; i < result->numparams; i++) {
1325 					if (params[i].fp != -1) {
1326 						close(params[i].fp);
1327 					}
1328 				}
1329 				efree(params);
1330 				RETURN_FALSE;
1331 			}
1332 
1333 			if (IS_SQL_BINARY(sqltype)) {
1334 				ctype = SQL_C_BINARY;
1335 			} else {
1336 				ctype = SQL_C_CHAR;
1337 			}
1338 
1339 			if (Z_STRLEN_PP(tmp) > 2 &&
1340 				Z_STRVAL_PP(tmp)[0] == '\'' &&
1341 				Z_STRVAL_PP(tmp)[Z_STRLEN_PP(tmp) - 1] == '\'') {
1342 
1343 				if (CHECK_ZVAL_NULL_PATH(*tmp)) {
1344 					RETURN_FALSE;
1345 				}
1346 				filename = estrndup(&Z_STRVAL_PP(tmp)[1], Z_STRLEN_PP(tmp) - 2);
1347 				filename[strlen(filename)] = '\0';
1348 
1349 				/* Check the basedir */
1350 				if (php_check_open_basedir(filename TSRMLS_CC)) {
1351 					efree(filename);
1352 					SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1353 					for (i = 0; i < result->numparams; i++) {
1354 						if (params[i].fp != -1) {
1355 							close(params[i].fp);
1356 						}
1357 					}
1358 					efree(params);
1359 					RETURN_FALSE;
1360 				}
1361 
1362 				if ((params[i-1].fp = open(filename,O_RDONLY)) == -1) {
1363 					php_error_docref(NULL TSRMLS_CC, E_WARNING,"Can't open file %s", filename);
1364 					SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1365 					for (i = 0; i < result->numparams; i++) {
1366 						if (params[i].fp != -1) {
1367 							close(params[i].fp);
1368 						}
1369 					}
1370 					efree(params);
1371 					efree(filename);
1372 					RETURN_FALSE;
1373 				}
1374 
1375 				efree(filename);
1376 
1377 				params[i-1].vallen = SQL_LEN_DATA_AT_EXEC(0);
1378 
1379 				rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
1380 									  ctype, sqltype, precision, scale,
1381 									  (void *)params[i-1].fp, 0,
1382 									  &params[i-1].vallen);
1383 			} else {
1384 #ifdef HAVE_DBMAKER
1385 				precision = params[i-1].vallen;
1386 #endif
1387 				if (otype == IS_NULL) {
1388 					params[i-1].vallen = SQL_NULL_DATA;
1389 				}
1390 
1391 				rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
1392 									  ctype, sqltype, precision, scale,
1393 									  Z_STRVAL_PP(tmp), 0,
1394 									  &params[i-1].vallen);
1395 			}
1396 			if (rc == SQL_ERROR) {
1397 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLBindParameter");
1398 				SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1399 				for (i = 0; i < result->numparams; i++) {
1400 					if (params[i].fp != -1) {
1401 						close(params[i].fp);
1402 					}
1403 				}
1404 				efree(params);
1405 				RETURN_FALSE;
1406 			}
1407 			zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
1408 		}
1409 	}
1410 	/* Close cursor, needed for doing multiple selects */
1411 	rc = SQLFreeStmt(result->stmt, SQL_CLOSE);
1412 
1413 	if (rc == SQL_ERROR) {
1414 		odbc_sql_error(result->conn_ptr, result->stmt, "SQLFreeStmt");
1415 	}
1416 
1417 	rc = SQLExecute(result->stmt);
1418 
1419 	result->fetched = 0;
1420 	if (rc == SQL_NEED_DATA) {
1421 		char buf[4096];
1422 		int fp, nbytes;
1423 		while (rc == SQL_NEED_DATA) {
1424 			rc = SQLParamData(result->stmt, (void*)&fp);
1425 			if (rc == SQL_NEED_DATA) {
1426 				while ((nbytes = read(fp, &buf, 4096)) > 0) {
1427 					SQLPutData(result->stmt, (void*)&buf, nbytes);
1428 				}
1429 			}
1430 		}
1431 	} else {
1432 		switch (rc) {
1433 			case SQL_SUCCESS:
1434 				break;
1435 			case SQL_NO_DATA_FOUND:
1436 			case SQL_SUCCESS_WITH_INFO:
1437 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
1438 				break;
1439 			default:
1440 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
1441 				RETVAL_FALSE;
1442 		}
1443 	}
1444 
1445 	if (result->numparams > 0) {
1446 		SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1447 		for(i = 0; i < result->numparams; i++) {
1448 			if (params[i].fp != -1) {
1449 				close(params[i].fp);
1450 			}
1451 		}
1452 		efree(params);
1453 	}
1454 
1455 	if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO || rc == SQL_NO_DATA_FOUND) {
1456 		RETVAL_TRUE;
1457 	}
1458 
1459 	if (result->numcols == 0) {
1460 		SQLNumResultCols(result->stmt, &(result->numcols));
1461 
1462 		if (result->numcols > 0) {
1463 			if (!odbc_bindcols(result TSRMLS_CC)) {
1464 				efree(result);
1465 				RETVAL_FALSE;
1466 			}
1467 		} else {
1468 			result->values = NULL;
1469 		}
1470 	}
1471 }
1472 /* }}} */
1473 
1474 /* {{{ proto string odbc_cursor(resource result_id)
1475    Get cursor name */
PHP_FUNCTION(odbc_cursor)1476 PHP_FUNCTION(odbc_cursor)
1477 {
1478 	zval *pv_res;
1479 	SQLUSMALLINT max_len;
1480 	SQLSMALLINT len;
1481 	char *cursorname;
1482    	odbc_result *result;
1483 	RETCODE rc;
1484 
1485 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1486 		return;
1487 	}
1488 
1489 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1490 
1491 	rc = SQLGetInfo(result->conn_ptr->hdbc,SQL_MAX_CURSOR_NAME_LEN, (void *)&max_len,sizeof(max_len),&len);
1492 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1493 		RETURN_FALSE;
1494 	}
1495 
1496 	if (max_len > 0) {
1497 		cursorname = emalloc(max_len + 1);
1498 		rc = SQLGetCursorName(result->stmt,cursorname,(SQLSMALLINT)max_len,&len);
1499 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1500 			char        state[6];     /* Not used */
1501 	 		SQLINTEGER  error;        /* Not used */
1502 			char        errormsg[SQL_MAX_MESSAGE_LENGTH];
1503 			SQLSMALLINT errormsgsize; /* Not used */
1504 
1505 			SQLError( result->conn_ptr->henv, result->conn_ptr->hdbc,
1506 						result->stmt, state, &error, errormsg,
1507 						sizeof(errormsg)-1, &errormsgsize);
1508 			if (!strncmp(state,"S1015",5)) {
1509 				snprintf(cursorname, max_len+1, "php_curs_%d", (int)result->stmt);
1510 				if (SQLSetCursorName(result->stmt,cursorname,SQL_NTS) != SQL_SUCCESS) {
1511 					odbc_sql_error(result->conn_ptr, result->stmt, "SQLSetCursorName");
1512 					RETVAL_FALSE;
1513 				} else {
1514 					RETVAL_STRING(cursorname,1);
1515 				}
1516 			} else {
1517 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
1518 				RETVAL_FALSE;
1519 			}
1520 		} else {
1521 			RETVAL_STRING(cursorname,1);
1522 		}
1523 		efree(cursorname);
1524 	} else {
1525 		RETVAL_FALSE;
1526 	}
1527 }
1528 /* }}} */
1529 
1530 #ifdef HAVE_SQLDATASOURCES
1531 /* {{{ proto array odbc_data_source(resource connection_id, int fetch_type)
1532    Return information about the currently connected data source */
PHP_FUNCTION(odbc_data_source)1533 PHP_FUNCTION(odbc_data_source)
1534 {
1535 	zval *zv_conn;
1536 	long zv_fetch_type;
1537 	RETCODE rc = 0; /* assume all is good */
1538 	odbc_connection *conn;
1539 	UCHAR server_name[100], desc[200];
1540 	SQLSMALLINT len1=0, len2=0, fetch_type;
1541 
1542 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zv_conn, &zv_fetch_type) == FAILURE) {
1543 		return;
1544 	}
1545 
1546 	fetch_type = (SQLSMALLINT) zv_fetch_type;
1547 
1548 	if (!(fetch_type == SQL_FETCH_FIRST || fetch_type == SQL_FETCH_NEXT)) {
1549 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fetch type (%d)", fetch_type);
1550 		RETURN_FALSE;
1551 	}
1552 
1553 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &zv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1554 
1555 	/* now we have the "connection" lets call the DataSource object */
1556 	rc = SQLDataSources(conn->henv,
1557 			fetch_type,
1558 			server_name,
1559 			(SQLSMALLINT)sizeof(server_name),
1560 			&len1,
1561 			desc,
1562 			(SQLSMALLINT)sizeof(desc),
1563 			&len2);
1564 
1565 	if (rc != SQL_SUCCESS) {
1566 		/* ummm.... he did it */
1567 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLDataSources");
1568 		RETURN_FALSE;
1569 	}
1570 
1571 	if (len1 == 0 || len2 == 0) {
1572 		/* we have a non-valid entry... so stop the looping */
1573 		RETURN_FALSE;
1574 	}
1575 
1576 	array_init(return_value);
1577 
1578 	add_assoc_string_ex(return_value, "server", sizeof("server"), server_name, 1);
1579 	add_assoc_string_ex(return_value, "description", sizeof("description"), desc, 1);
1580 
1581 }
1582 /* }}} */
1583 #endif /* HAVE_SQLDATASOURCES */
1584 
1585 /* {{{ proto resource odbc_exec(resource connection_id, string query [, int flags])
1586    Prepare and execute an SQL statement */
1587 /* XXX Use flags */
PHP_FUNCTION(odbc_exec)1588 PHP_FUNCTION(odbc_exec)
1589 {
1590 	zval *pv_conn;
1591 	long pv_flags;
1592 	char *query;
1593 	int numArgs, query_len;
1594 	odbc_result *result = NULL;
1595 	odbc_connection *conn;
1596 	RETCODE rc;
1597 #ifdef HAVE_SQL_EXTENDED_FETCH
1598 	SQLUINTEGER      scrollopts;
1599 #endif
1600 
1601 	numArgs = ZEND_NUM_ARGS();
1602 
1603 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &pv_conn, &query, &query_len, &pv_flags) == FAILURE) {
1604 		return;
1605 	}
1606 
1607 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1608 
1609 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
1610 
1611 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
1612 	if (rc == SQL_INVALID_HANDLE) {
1613 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
1614 		efree(result);
1615 		RETURN_FALSE;
1616 	}
1617 
1618 	if (rc == SQL_ERROR) {
1619 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
1620 		efree(result);
1621 		RETURN_FALSE;
1622 	}
1623 
1624 #ifdef HAVE_SQL_EXTENDED_FETCH
1625 	/* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
1626 	   whether Driver supports ExtendedFetch */
1627 	rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
1628 	if (rc == SQL_SUCCESS) {
1629 		if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
1630 			/* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
1631 			   type if not possible.
1632 			 */
1633 			SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
1634 		}
1635 	} else {
1636 		result->fetch_abs = 0;
1637 	}
1638 #endif
1639 
1640 	rc = SQLExecDirect(result->stmt, query, SQL_NTS);
1641 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA_FOUND) {
1642 		/* XXX FIXME we should really check out SQLSTATE with SQLError
1643 		 * in case rc is SQL_SUCCESS_WITH_INFO here.
1644 		 */
1645 		odbc_sql_error(conn, result->stmt, "SQLExecDirect");
1646 		SQLFreeStmt(result->stmt, SQL_DROP);
1647 		efree(result);
1648 		RETURN_FALSE;
1649 	}
1650 
1651 	SQLNumResultCols(result->stmt, &(result->numcols));
1652 
1653 	/* For insert, update etc. cols == 0 */
1654 	if (result->numcols > 0) {
1655 		if (!odbc_bindcols(result TSRMLS_CC)) {
1656 			efree(result);
1657 			RETURN_FALSE;
1658 		}
1659 	} else {
1660 		result->values = NULL;
1661 	}
1662 	zend_list_addref(conn->id);
1663 	result->conn_ptr = conn;
1664 	result->fetched = 0;
1665 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1666 }
1667 /* }}} */
1668 
1669 #ifdef PHP_ODBC_HAVE_FETCH_HASH
1670 #define ODBC_NUM  1
1671 #define ODBC_OBJECT  2
1672 
1673 /* {{{ php_odbc_fetch_hash */
php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS,int result_type)1674 static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
1675 {
1676 	int i;
1677 	odbc_result *result;
1678 	RETCODE rc;
1679 	SQLSMALLINT sql_c_type;
1680 	char *buf = NULL;
1681 #ifdef HAVE_SQL_EXTENDED_FETCH
1682 	SQLULEN crow;
1683 	SQLUSMALLINT RowStatus[1];
1684 	SQLLEN rownum;
1685 	zval *pv_res, *tmp;
1686 	long pv_row = -1;
1687 
1688 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
1689 		return;
1690 	}
1691 
1692 	rownum = pv_row;
1693 #else
1694 	zval *pv_res, *tmp;
1695 
1696 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1697 		return;
1698 	}
1699 #endif
1700 
1701 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1702 
1703 	if (result->numcols == 0) {
1704 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1705 		RETURN_FALSE;
1706 	}
1707 
1708 #ifdef HAVE_SQL_EXTENDED_FETCH
1709 	if (result->fetch_abs) {
1710 		if (rownum > 0) {
1711 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1712 		} else {
1713 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1714 		}
1715 	} else
1716 #endif
1717 	rc = SQLFetch(result->stmt);
1718 
1719 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1720 		RETURN_FALSE;
1721 	}
1722 
1723 	array_init(return_value);
1724 
1725 #ifdef HAVE_SQL_EXTENDED_FETCH
1726 	if (rownum > 0 && result->fetch_abs)
1727 		result->fetched = rownum;
1728 	else
1729 #endif
1730 		result->fetched++;
1731 
1732 	for(i = 0; i < result->numcols; i++) {
1733 		ALLOC_INIT_ZVAL(tmp);
1734 		Z_TYPE_P(tmp) = IS_STRING;
1735 		Z_STRLEN_P(tmp) = 0;
1736 		sql_c_type = SQL_C_CHAR;
1737 
1738 		switch(result->values[i].coltype) {
1739 			case SQL_BINARY:
1740 			case SQL_VARBINARY:
1741 			case SQL_LONGVARBINARY:
1742 				if (result->binmode <= 0) {
1743 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1744 					break;
1745 				}
1746 				if (result->binmode == 1) {
1747 					sql_c_type = SQL_C_BINARY;
1748 				}
1749 			case SQL_LONGVARCHAR:
1750 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
1751 			case SQL_WLONGVARCHAR:
1752 #endif
1753 				if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
1754 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1755 					break;
1756 				}
1757 				if (buf == NULL) {
1758 					buf = emalloc(result->longreadlen + 1);
1759 				}
1760 
1761 				rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1), sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
1762 
1763 				if (rc == SQL_ERROR) {
1764 					odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
1765 					efree(buf);
1766 					RETURN_FALSE;
1767 				}
1768 
1769 				if (rc == SQL_SUCCESS_WITH_INFO) {
1770 					Z_STRLEN_P(tmp) = result->longreadlen;
1771 				} else if (result->values[i].vallen == SQL_NULL_DATA) {
1772 					ZVAL_NULL(tmp);
1773 					break;
1774 				} else {
1775 					Z_STRLEN_P(tmp) = result->values[i].vallen;
1776 				}
1777 				Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
1778 				break;
1779 
1780 			default:
1781 				if (result->values[i].vallen == SQL_NULL_DATA) {
1782 					ZVAL_NULL(tmp);
1783 					break;
1784 				}
1785 				Z_STRLEN_P(tmp) = result->values[i].vallen;
1786 				Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
1787 				break;
1788 		}
1789 
1790 		if (result_type & ODBC_NUM) {
1791 			zend_hash_index_update(Z_ARRVAL_P(return_value), i, &tmp, sizeof(zval *), NULL);
1792 		} else {
1793 			if (!*(result->values[i].name) && Z_TYPE_P(tmp) == IS_STRING) {
1794 				zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(tmp),	Z_STRLEN_P(tmp)+1, &tmp, sizeof(zval *), NULL);
1795 			} else {
1796 				zend_hash_update(Z_ARRVAL_P(return_value), result->values[i].name, strlen(result->values[i].name)+1, &tmp, sizeof(zval *), NULL);
1797 			}
1798 		}
1799 	}
1800 	if (buf) {
1801 		efree(buf);
1802 	}
1803 }
1804 /* }}} */
1805 
1806 
1807 /* {{{ proto object odbc_fetch_object(int result [, int rownumber])
1808    Fetch a result row as an object */
PHP_FUNCTION(odbc_fetch_object)1809 PHP_FUNCTION(odbc_fetch_object)
1810 {
1811 	php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
1812 	if (Z_TYPE_P(return_value) == IS_ARRAY) {
1813 		object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1814 	}
1815 }
1816 /* }}} */
1817 
1818 /* {{{ proto array odbc_fetch_array(int result [, int rownumber])
1819    Fetch a result row as an associative array */
PHP_FUNCTION(odbc_fetch_array)1820 PHP_FUNCTION(odbc_fetch_array)
1821 {
1822 	php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
1823 }
1824 /* }}} */
1825 #endif
1826 
1827 /* {{{ proto int odbc_fetch_into(resource result_id, array &result_array, [, int rownumber])
1828    Fetch one result row into an array */
PHP_FUNCTION(odbc_fetch_into)1829 PHP_FUNCTION(odbc_fetch_into)
1830 {
1831 	int i;
1832 	odbc_result *result;
1833 	RETCODE rc;
1834 	SQLSMALLINT sql_c_type;
1835 	char *buf = NULL;
1836 	zval *pv_res, **pv_res_arr, *tmp;
1837 #ifdef HAVE_SQL_EXTENDED_FETCH
1838 	long pv_row = 0;
1839 	SQLULEN crow;
1840 	SQLUSMALLINT RowStatus[1];
1841 	SQLLEN rownum = -1;
1842 #endif /* HAVE_SQL_EXTENDED_FETCH */
1843 
1844 #ifdef HAVE_SQL_EXTENDED_FETCH
1845 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) {
1846 		return;
1847 	}
1848 
1849 	rownum = pv_row;
1850 #else
1851 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_res_arr) == FAILURE) {
1852 		return;
1853 	}
1854 #endif /* HAVE_SQL_EXTENDED_FETCH */
1855 
1856 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1857 
1858 	if (result->numcols == 0) {
1859 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1860 		RETURN_FALSE;
1861 	}
1862 
1863 	if (Z_TYPE_PP(pv_res_arr) != IS_ARRAY) {
1864 		array_init(*pv_res_arr);
1865 	}
1866 
1867 #ifdef HAVE_SQL_EXTENDED_FETCH
1868 	if (result->fetch_abs) {
1869 		if (rownum > 0) {
1870 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1871 		} else {
1872 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1873 		}
1874 	} else
1875 #endif
1876 		rc = SQLFetch(result->stmt);
1877 
1878 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1879 		RETURN_FALSE;
1880 	}
1881 
1882 #ifdef HAVE_SQL_EXTENDED_FETCH
1883 	if (rownum > 0 && result->fetch_abs)
1884 		result->fetched = rownum;
1885 	else
1886 #endif
1887 		result->fetched++;
1888 
1889 	for(i = 0; i < result->numcols; i++) {
1890 		MAKE_STD_ZVAL(tmp);
1891 		Z_TYPE_P(tmp) = IS_STRING;
1892 		Z_STRLEN_P(tmp) = 0;
1893 		sql_c_type = SQL_C_CHAR;
1894 
1895 		switch(result->values[i].coltype) {
1896 			case SQL_BINARY:
1897 			case SQL_VARBINARY:
1898 			case SQL_LONGVARBINARY:
1899 				if (result->binmode <= 0) {
1900 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1901 					break;
1902 				}
1903 				if (result->binmode == 1) sql_c_type = SQL_C_BINARY;
1904 
1905 			case SQL_LONGVARCHAR:
1906 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
1907 			case SQL_WLONGVARCHAR:
1908 #endif
1909 				if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
1910 					Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1911 					break;
1912 				}
1913 
1914 				if (buf == NULL) {
1915 					buf = emalloc(result->longreadlen + 1);
1916 				}
1917 				rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
1918 
1919 				if (rc == SQL_ERROR) {
1920 					odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
1921 					efree(buf);
1922 					RETURN_FALSE;
1923 				}
1924 				if (rc == SQL_SUCCESS_WITH_INFO) {
1925 					Z_STRLEN_P(tmp) = result->longreadlen;
1926 				} else if (result->values[i].vallen == SQL_NULL_DATA) {
1927 					ZVAL_NULL(tmp);
1928 					break;
1929 				} else {
1930 					Z_STRLEN_P(tmp) = result->values[i].vallen;
1931 				}
1932 				Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
1933 				break;
1934 
1935 			default:
1936 				if (result->values[i].vallen == SQL_NULL_DATA) {
1937 					ZVAL_NULL(tmp);
1938 					break;
1939 				}
1940 				Z_STRLEN_P(tmp) = result->values[i].vallen;
1941 				Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
1942 				break;
1943 		}
1944 		zend_hash_index_update(Z_ARRVAL_PP(pv_res_arr), i, &tmp, sizeof(zval *), NULL);
1945 	}
1946 	if (buf) efree(buf);
1947 	RETURN_LONG(result->numcols);
1948 }
1949 /* }}} */
1950 
1951 /* {{{ proto bool solid_fetch_prev(resource result_id)
1952    */
1953 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
PHP_FUNCTION(solid_fetch_prev)1954 PHP_FUNCTION(solid_fetch_prev)
1955 {
1956 	odbc_result *result;
1957 	RETCODE rc;
1958 	zval *pv_res;
1959 
1960 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1961 		return;
1962 	}
1963 
1964 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1965 	if (result->numcols == 0) {
1966 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1967 		RETURN_FALSE;
1968 	}
1969 	rc = SQLFetchPrev(result->stmt);
1970 
1971 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1972 		RETURN_FALSE;
1973 	}
1974 
1975 	if (result->fetched > 1) {
1976 		result->fetched--;
1977 	}
1978 
1979 	RETURN_TRUE;
1980 }
1981 #endif
1982 /* }}} */
1983 
1984 /* {{{ proto bool odbc_fetch_row(resource result_id [, int row_number])
1985    Fetch a row */
PHP_FUNCTION(odbc_fetch_row)1986 PHP_FUNCTION(odbc_fetch_row)
1987 {
1988 	SQLLEN rownum;
1989 	odbc_result *result;
1990 	RETCODE rc;
1991 	zval *pv_res;
1992 	long pv_row = 1;
1993 #ifdef HAVE_SQL_EXTENDED_FETCH
1994 	SQLULEN crow;
1995 	SQLUSMALLINT RowStatus[1];
1996 #endif
1997 
1998 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
1999 		return;
2000 	}
2001 
2002 	rownum = pv_row;
2003 
2004 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2005 
2006 	if (result->numcols == 0) {
2007 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2008 		RETURN_FALSE;
2009 	}
2010 
2011 #ifdef HAVE_SQL_EXTENDED_FETCH
2012 	if (result->fetch_abs) {
2013 		if (ZEND_NUM_ARGS() > 1) {
2014 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
2015 		} else {
2016 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2017 		}
2018 	} else
2019 #endif
2020 		rc = SQLFetch(result->stmt);
2021 
2022 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2023 		RETURN_FALSE;
2024 	}
2025 
2026 	if (ZEND_NUM_ARGS() > 1) {
2027 		result->fetched = rownum;
2028 	} else {
2029 		result->fetched++;
2030 	}
2031 
2032 	RETURN_TRUE;
2033 }
2034 /* }}} */
2035 
2036 /* {{{ proto mixed odbc_result(resource result_id, mixed field)
2037    Get result data */
PHP_FUNCTION(odbc_result)2038 PHP_FUNCTION(odbc_result)
2039 {
2040 	char *field;
2041 	int field_ind;
2042 	SQLSMALLINT sql_c_type = SQL_C_CHAR;
2043 	odbc_result *result;
2044 	int i = 0;
2045 	RETCODE rc;
2046 	SQLLEN	fieldsize;
2047 	zval *pv_res, **pv_field;
2048 #ifdef HAVE_SQL_EXTENDED_FETCH
2049 	SQLULEN crow;
2050 	SQLUSMALLINT RowStatus[1];
2051 #endif
2052 
2053 	field_ind = -1;
2054 	field = NULL;
2055 
2056 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_field) == FAILURE) {
2057 		return;
2058 	}
2059 
2060 	if (Z_TYPE_PP(pv_field) == IS_STRING) {
2061 		field = Z_STRVAL_PP(pv_field);
2062 	} else {
2063 		convert_to_long_ex(pv_field);
2064 		field_ind = Z_LVAL_PP(pv_field) - 1;
2065 	}
2066 
2067 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2068 
2069 	if ((result->numcols == 0)) {
2070 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2071 		RETURN_FALSE;
2072 	}
2073 
2074 	/* get field index if the field parameter was a string */
2075 	if (field != NULL) {
2076 		if (result->values == NULL) {
2077 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set contains no data");
2078 			RETURN_FALSE;
2079 		}
2080 
2081 		for(i = 0; i < result->numcols; i++) {
2082 			if (!strcasecmp(result->values[i].name, field)) {
2083 				field_ind = i;
2084 				break;
2085 			}
2086 		}
2087 
2088 		if (field_ind < 0) {
2089 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field %s not found", field);
2090 			RETURN_FALSE;
2091 		}
2092 	} else {
2093 		/* check for limits of field_ind if the field parameter was an int */
2094 		if (field_ind >= result->numcols || field_ind < 0) {
2095 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index is larger than the number of fields");
2096 			RETURN_FALSE;
2097 		}
2098 	}
2099 
2100 	if (result->fetched == 0) {
2101 		/* User forgot to call odbc_fetch_row(), or wants to reload the results, do it now */
2102 #ifdef HAVE_SQL_EXTENDED_FETCH
2103 		if (result->fetch_abs)
2104 			rc = SQLExtendedFetch(result->stmt, SQL_FETCH_NEXT, 1, &crow,RowStatus);
2105 		else
2106 #endif
2107 			rc = SQLFetch(result->stmt);
2108 
2109 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2110 			RETURN_FALSE;
2111 		}
2112 
2113 		result->fetched++;
2114 	}
2115 
2116 	switch(result->values[field_ind].coltype) {
2117 		case SQL_BINARY:
2118 		case SQL_VARBINARY:
2119 		case SQL_LONGVARBINARY:
2120 			if (result->binmode <= 1) {
2121 				sql_c_type = SQL_C_BINARY;
2122 			}
2123 			if (result->binmode <= 0) {
2124 				break;
2125 			}
2126 		case SQL_LONGVARCHAR:
2127 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
2128 		case SQL_WLONGVARCHAR:
2129 #endif
2130 			if (IS_SQL_LONG(result->values[field_ind].coltype)) {
2131 				if (result->longreadlen <= 0) {
2132 				   break;
2133 				} else {
2134 				   fieldsize = result->longreadlen;
2135 				}
2136 			} else {
2137 			   SQLColAttributes(result->stmt, (SQLUSMALLINT)(field_ind + 1),
2138 					   			(SQLUSMALLINT)((sql_c_type == SQL_C_BINARY) ? SQL_COLUMN_LENGTH :
2139 					   			SQL_COLUMN_DISPLAY_SIZE),
2140 					   			NULL, 0, NULL, &fieldsize);
2141 			}
2142 			/* For char data, the length of the returned string will be longreadlen - 1 */
2143 			fieldsize = (result->longreadlen <= 0) ? 4096 : result->longreadlen;
2144 			field = emalloc(fieldsize);
2145 
2146 		/* SQLGetData will truncate CHAR data to fieldsize - 1 bytes and append \0.
2147 		 * For binary data it is truncated to fieldsize bytes.
2148 		 */
2149 			rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1), sql_c_type,
2150 							field, fieldsize, &result->values[field_ind].vallen);
2151 
2152 			if (rc == SQL_ERROR) {
2153 				odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2154 				efree(field);
2155 				RETURN_FALSE;
2156 			}
2157 
2158 			if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2159 				efree(field);
2160 				RETURN_NULL();
2161 			} else if (rc == SQL_NO_DATA_FOUND) {
2162 				efree(field);
2163 				RETURN_FALSE;
2164 			}
2165 			/* Reduce fieldlen by 1 if we have char data. One day we might
2166 			   have binary strings... */
2167 			if ((result->values[field_ind].coltype == SQL_LONGVARCHAR)
2168 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
2169 			    || (result->values[field_ind].coltype == SQL_WLONGVARCHAR)
2170 #endif
2171 			) {
2172 				fieldsize -= 1;
2173 			}
2174 			/* Don't duplicate result, saves one emalloc.
2175 			   For SQL_SUCCESS, the length is in vallen.
2176 			 */
2177 			RETURN_STRINGL(field, (rc == SQL_SUCCESS_WITH_INFO) ? fieldsize : result->values[field_ind].vallen, 0);
2178 			break;
2179 
2180 		default:
2181 			if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2182 				RETURN_NULL();
2183 			} else {
2184 				RETURN_STRINGL(result->values[field_ind].value, result->values[field_ind].vallen, 1);
2185 			}
2186 			break;
2187 	}
2188 
2189 /* If we come here, output unbound LONG and/or BINARY column data to the client */
2190 
2191 	/* We emalloc 1 byte more for SQL_C_CHAR (trailing \0) */
2192 	fieldsize = (sql_c_type == SQL_C_CHAR) ? 4096 : 4095;
2193 	field = emalloc(fieldsize);
2194 
2195 	/* Call SQLGetData() until SQL_SUCCESS is returned */
2196 	while(1) {
2197 		rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1),sql_c_type, field, fieldsize, &result->values[field_ind].vallen);
2198 
2199 		if (rc == SQL_ERROR) {
2200 			odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2201 			efree(field);
2202 			RETURN_FALSE;
2203 		}
2204 
2205 		if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2206 			efree(field);
2207 			RETURN_NULL();
2208 		}
2209 		/* chop the trailing \0 by outputing only 4095 bytes */
2210 		PHPWRITE(field,(rc == SQL_SUCCESS_WITH_INFO) ? 4095 : result->values[field_ind].vallen);
2211 
2212 		if (rc == SQL_SUCCESS) { /* no more data avail */
2213 			efree(field);
2214 			RETURN_TRUE;
2215 		}
2216 	}
2217 	RETURN_TRUE;
2218 }
2219 /* }}} */
2220 
2221 /* {{{ proto int odbc_result_all(resource result_id [, string format])
2222    Print result as HTML table */
PHP_FUNCTION(odbc_result_all)2223 PHP_FUNCTION(odbc_result_all)
2224 {
2225 	char *buf = NULL;
2226 	odbc_result *result;
2227 	RETCODE rc;
2228 	zval *pv_res;
2229 	char *pv_format = NULL;
2230 	int i, pv_format_len = 0;
2231 	SQLSMALLINT sql_c_type;
2232 #ifdef HAVE_SQL_EXTENDED_FETCH
2233 	SQLULEN crow;
2234 	SQLUSMALLINT RowStatus[1];
2235 #endif
2236 
2237 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s", &pv_res, &pv_format, &pv_format_len) == FAILURE) {
2238 		return;
2239 	}
2240 
2241 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2242 
2243 	if (result->numcols == 0) {
2244 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2245 		RETURN_FALSE;
2246 	}
2247 #ifdef HAVE_SQL_EXTENDED_FETCH
2248 	if (result->fetch_abs)
2249 		rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2250 	else
2251 #endif
2252 		rc = SQLFetch(result->stmt);
2253 
2254 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2255 		php_printf("<h2>No rows found</h2>\n");
2256 		RETURN_LONG(0);
2257 	}
2258 
2259 	/* Start table tag */
2260 	if (ZEND_NUM_ARGS() == 1) {
2261 		php_printf("<table><tr>");
2262 	} else {
2263 		php_printf("<table %s ><tr>", pv_format);
2264 	}
2265 
2266 	for (i = 0; i < result->numcols; i++) {
2267 		php_printf("<th>%s</th>", result->values[i].name);
2268 	}
2269 
2270 	php_printf("</tr>\n");
2271 
2272 	while(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
2273 		result->fetched++;
2274 		php_printf("<tr>");
2275 		for(i = 0; i < result->numcols; i++) {
2276 			sql_c_type = SQL_C_CHAR;
2277 			switch(result->values[i].coltype) {
2278 				case SQL_BINARY:
2279 				case SQL_VARBINARY:
2280 				case SQL_LONGVARBINARY:
2281 					if (result->binmode <= 0) {
2282 						php_printf("<td>Not printable</td>");
2283 						break;
2284 					}
2285 					if (result->binmode <= 1) sql_c_type = SQL_C_BINARY;
2286 				case SQL_LONGVARCHAR:
2287 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
2288 				case SQL_WLONGVARCHAR:
2289 #endif
2290 					if (IS_SQL_LONG(result->values[i].coltype) &&
2291 						result->longreadlen <= 0) {
2292 						php_printf("<td>Not printable</td>");
2293 						break;
2294 					}
2295 
2296 					if (buf == NULL) {
2297 						buf = emalloc(result->longreadlen);
2298 					}
2299 
2300 					rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen, &result->values[i].vallen);
2301 
2302 					php_printf("<td>");
2303 
2304 					if (rc == SQL_ERROR) {
2305 						odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2306 						php_printf("</td></tr></table>");
2307 						efree(buf);
2308 						RETURN_FALSE;
2309 					}
2310 					if (rc == SQL_SUCCESS_WITH_INFO) {
2311 						PHPWRITE(buf, result->longreadlen);
2312 					} else if (result->values[i].vallen == SQL_NULL_DATA) {
2313 						php_printf("<td>NULL</td>");
2314 						break;
2315 					} else {
2316 						PHPWRITE(buf, result->values[i].vallen);
2317 					}
2318 					php_printf("</td>");
2319 					break;
2320 				default:
2321 					if (result->values[i].vallen == SQL_NULL_DATA) {
2322 						php_printf("<td>NULL</td>");
2323 					} else {
2324 						php_printf("<td>%s</td>", result->values[i].value);
2325 					}
2326 					break;
2327 			}
2328 		}
2329    		php_printf("</tr>\n");
2330 
2331 #ifdef HAVE_SQL_EXTENDED_FETCH
2332 		if (result->fetch_abs)
2333 			rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2334 		else
2335 #endif
2336 			rc = SQLFetch(result->stmt);
2337 	}
2338 	php_printf("</table>\n");
2339 	if (buf) efree(buf);
2340 	RETURN_LONG(result->fetched);
2341 }
2342 /* }}} */
2343 
2344 /* {{{ proto bool odbc_free_result(resource result_id)
2345    Free resources associated with a result */
PHP_FUNCTION(odbc_free_result)2346 PHP_FUNCTION(odbc_free_result)
2347 {
2348 	zval *pv_res;
2349 	odbc_result *result;
2350 	int i;
2351 
2352 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2353 		return;
2354 	}
2355 
2356 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2357 	if (result->values) {
2358 		for (i = 0; i < result->numcols; i++) {
2359 			if (result->values[i].value) {
2360 				efree(result->values[i].value);
2361 			}
2362 		}
2363 		efree(result->values);
2364 		result->values = NULL;
2365 	}
2366 
2367 	zend_list_delete(Z_LVAL_P(pv_res));
2368 
2369 	RETURN_TRUE;
2370 }
2371 /* }}} */
2372 
2373 /* {{{ proto resource odbc_connect(string DSN, string user, string password [, int cursor_option])
2374    Connect to a datasource */
PHP_FUNCTION(odbc_connect)2375 PHP_FUNCTION(odbc_connect)
2376 {
2377 	odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2378 }
2379 /* }}} */
2380 
2381 /* {{{ proto resource odbc_pconnect(string DSN, string user, string password [, int cursor_option])
2382    Establish a persistent connection to a datasource */
PHP_FUNCTION(odbc_pconnect)2383 PHP_FUNCTION(odbc_pconnect)
2384 {
2385 	odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2386 }
2387 /* }}} */
2388 
2389 /* {{{ odbc_sqlconnect */
odbc_sqlconnect(odbc_connection ** conn,char * db,char * uid,char * pwd,int cur_opt,int persistent TSRMLS_DC)2390 int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int cur_opt, int persistent TSRMLS_DC)
2391 {
2392 	RETCODE rc;
2393 
2394 	*conn = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent);
2395 	(*conn)->persistent = persistent;
2396 	SQLAllocEnv(&((*conn)->henv));
2397 	SQLAllocConnect((*conn)->henv, &((*conn)->hdbc));
2398 
2399 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
2400 	SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION,
2401 			SQL_SOLID_XLATOPT_NOCNV);
2402 #endif
2403 #ifdef HAVE_ODBC_ROUTER
2404 	{
2405 #define CONNSTRSIZE 2048
2406 	 char *lpszConnStr = emalloc(CONNSTRSIZE);
2407 	 if (lpszConnStr && db) {
2408 		 short cbszConnStr;
2409 		 if (strstr(db, ";")) {
2410 			 /* the caller has apparently passed a connection-string */
2411 			 if (strstr(db, "uid") || strstr(db, "UID")) {
2412 				 uid = NULL;
2413 			 }
2414 			 if (strstr(db, "pwd") || strstr(db, "PWD")) {
2415 				 pwd = NULL;
2416 			 }
2417 			 strlcpy( lpszConnStr, db, CONNSTRSIZE);
2418 		 }
2419 		 else {
2420 			 strcpy(lpszConnStr, "DSN=");
2421 			 strlcat(lpszConnStr, db, CONNSTRSIZE);
2422 		 }
2423 		 if (uid) {
2424 			 if (uid[0]) {
2425 				 strlcat(lpszConnStr, ";UID=", CONNSTRSIZE);
2426 				 strlcat(lpszConnStr, uid, CONNSTRSIZE);
2427 				 strlcat(lpszConnStr, ";", CONNSTRSIZE);
2428 			 }
2429 			 if (pwd) {
2430 				 if (pwd[0]) {
2431 					 strlcat(lpszConnStr, "PWD=", CONNSTRSIZE);
2432 					 strlcat(lpszConnStr, pwd, CONNSTRSIZE);
2433 					 strlcat(lpszConnStr, ";", CONNSTRSIZE);
2434 				 }
2435 			 }
2436 		 }
2437 		 rc = SQLDriverConnect((*conn)->hdbc, NULL, lpszConnStr, SQL_NTS, lpszConnStr, CONNSTRSIZE, &cbszConnStr, SQL_DRIVER_NOPROMPT);
2438 		 efree(lpszConnStr);
2439 	 }
2440 	}
2441 #else
2442 #ifdef HAVE_OPENLINK
2443 	{
2444 		char dsnbuf[1024];
2445 		short dsnbuflen;
2446 
2447 		rc = SQLDriverConnect((*conn)->hdbc, NULL, db, SQL_NTS,	dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
2448 	}
2449 #else
2450 	if (cur_opt != SQL_CUR_DEFAULT) {
2451 		rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt);
2452 		if (rc != SQL_SUCCESS) {  /* && rc != SQL_SUCCESS_WITH_INFO ? */
2453 			odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption");
2454 			SQLFreeConnect((*conn)->hdbc);
2455 			pefree(*conn, persistent);
2456 			return FALSE;
2457 		}
2458 	}
2459 /*  Possible fix for bug #10250
2460  *  Needs testing on UnixODBC < 2.0.5 though. */
2461 #if defined(HAVE_EMPRESS) || defined(HAVE_UNIXODBC) || defined(PHP_WIN32) || defined (HAVE_IODBC)
2462 /* *  Uncomment the line above, and comment line below to fully test
2463  * #ifdef HAVE_EMPRESS */
2464 	{
2465 		int     direct = 0;
2466 		char    dsnbuf[1024];
2467 		short   dsnbuflen;
2468 		char    *ldb = 0;
2469 		int		ldb_len = 0;
2470 
2471 		if (strstr((char*)db, ";")) {
2472 			direct = 1;
2473 			if (uid && !strstr ((char*)db, "uid") && !strstr((char*)db, "UID")) {
2474 				spprintf(&ldb, 0, "%s;UID=%s;PWD=%s", db, uid, pwd);
2475 			} else {
2476 				ldb_len = strlen(db)+1;
2477 				ldb = (char*) emalloc(ldb_len);
2478 				memcpy(ldb, db, ldb_len);
2479 			}
2480 		}
2481 
2482 		if (direct) {
2483 			rc = SQLDriverConnect((*conn)->hdbc, NULL, ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
2484 		} else {
2485 			rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
2486 		}
2487 
2488 		if (ldb) {
2489 			efree(ldb);
2490 		}
2491 	}
2492 #else
2493 	rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
2494 #endif
2495 #endif
2496 #endif
2497 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2498 		odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLConnect");
2499 		SQLFreeConnect((*conn)->hdbc);
2500 		pefree((*conn), persistent);
2501 		return FALSE;
2502 	}
2503 /*	(*conn)->open = 1;*/
2504 	return TRUE;
2505 }
2506 /* }}} */
2507 
2508 /* Persistent connections: two list-types le_pconn, le_conn and a plist
2509  * where hashed connection info is stored together with index pointer to
2510  * the actual link of type le_pconn in the list. Only persistent
2511  * connections get hashed up. Normal connections use existing pconnections.
2512  * Maybe this has to change with regard to transactions on pconnections?
2513  * Possibly set autocommit to on on request shutdown.
2514  *
2515  * We do have to hash non-persistent connections, and reuse connections.
2516  * In the case where two connects were being made, without closing the first
2517  * connect, access violations were occuring.  This is because some of the
2518  * "globals" in this module should actualy be per-connection variables.  I
2519  * simply fixed things to get them working for now.  Shane
2520  */
2521 /* {{{ odbc_do_connect */
odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent)2522 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
2523 {
2524 	char *db, *uid, *pwd;
2525 	int db_len, uid_len, pwd_len;
2526 	long pv_opt = SQL_CUR_DEFAULT;
2527 	odbc_connection *db_conn;
2528 	char *hashed_details;
2529 	int hashed_len, cur_opt;
2530 
2531 	/*  Now an optional 4th parameter specifying the cursor type
2532 	 *  defaulting to the cursors default
2533 	 */
2534 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &db, &db_len, &uid, &uid_len, &pwd, &pwd_len, &pv_opt) == FAILURE) {
2535 		return;
2536 	}
2537 
2538 	cur_opt = pv_opt;
2539 
2540 	if (ZEND_NUM_ARGS() > 3) {
2541 		/* Confirm the cur_opt range */
2542 		if (! (cur_opt == SQL_CUR_USE_IF_NEEDED ||
2543 			cur_opt == SQL_CUR_USE_ODBC ||
2544 			cur_opt == SQL_CUR_USE_DRIVER ||
2545 			cur_opt == SQL_CUR_DEFAULT) ) {
2546 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Cursor type (%d)", cur_opt);
2547 			RETURN_FALSE;
2548 		}
2549 	}
2550 
2551 	if (ODBCG(allow_persistent) <= 0) {
2552 		persistent = 0;
2553 	}
2554 
2555 	hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt);
2556 
2557 	/* FIXME the idea of checking to see if our connection is already persistent
2558 		is good, but it adds a lot of overhead to non-persistent connections.  We
2559 		should look and see if we can fix that somehow */
2560 	/* try to find if we already have this link in our persistent list,
2561 	 * no matter if it is to be persistent or not
2562 	 */
2563 
2564 try_and_get_another_connection:
2565 
2566 	if (persistent) {
2567 		zend_rsrc_list_entry *le;
2568 
2569 		/* the link is not in the persistent list */
2570 		if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_len + 1, (void **) &le)	== FAILURE) {
2571 			zend_rsrc_list_entry new_le;
2572 
2573 			if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
2574 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", ODBCG(num_links));
2575 				efree(hashed_details);
2576 				RETURN_FALSE;
2577 			}
2578 			if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) {
2579 				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open persistent links (%ld)", ODBCG(num_persistent));
2580 				efree(hashed_details);
2581 				RETURN_FALSE;
2582 			}
2583 
2584 			if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1 TSRMLS_CC)) {
2585 				efree(hashed_details);
2586 				RETURN_FALSE;
2587 			}
2588 
2589 			Z_TYPE(new_le) = le_pconn;
2590 			new_le.ptr = db_conn;
2591 			if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_len + 1, &new_le,
2592 						sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
2593 				free(db_conn);
2594 				efree(hashed_details);
2595 				RETURN_FALSE;
2596 			}
2597 			ODBCG(num_persistent)++;
2598 			ODBCG(num_links)++;
2599 			db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
2600 		} else { /* found connection */
2601 			if (Z_TYPE_P(le) != le_pconn) {
2602 				RETURN_FALSE;
2603 			}
2604 			/*
2605 			 * check to see if the connection is still valid
2606 			 */
2607 			db_conn = (odbc_connection *)le->ptr;
2608 
2609 			/*
2610 			 * check to see if the connection is still in place (lurcher)
2611 			 */
2612 			if(ODBCG(check_persistent)){
2613 				RETCODE ret;
2614 				UCHAR d_name[32];
2615 				SQLSMALLINT len;
2616 
2617 				ret = SQLGetInfo(db_conn->hdbc,
2618 					SQL_DATA_SOURCE_READ_ONLY,
2619 					d_name, sizeof(d_name), &len);
2620 
2621 				if(ret != SQL_SUCCESS || len == 0) {
2622 					zend_hash_del(&EG(persistent_list), hashed_details, hashed_len + 1);
2623 					/* Commented out to fix a possible double closure error
2624 					 * when working with persistent connections as submitted by
2625 					 * bug #15758
2626 					 *
2627 					 * safe_odbc_disconnect(db_conn->hdbc);
2628 					 * SQLFreeConnect(db_conn->hdbc);
2629 					 */
2630 					goto try_and_get_another_connection;
2631 				}
2632 			}
2633 		}
2634 		db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
2635 	} else { /* non persistent */
2636 		zend_rsrc_list_entry *index_ptr, new_index_ptr;
2637 
2638 		if (zend_hash_find(&EG(regular_list), hashed_details, hashed_len + 1, (void **) &index_ptr) == SUCCESS) {
2639 			int type, conn_id;
2640 			void *ptr;
2641 
2642 			if (Z_TYPE_P(index_ptr) != le_index_ptr) {
2643 				RETURN_FALSE;
2644 			}
2645 			conn_id = (int)index_ptr->ptr;
2646 			ptr = zend_list_find(conn_id, &type);   /* check if the connection is still there */
2647 
2648 			if (ptr && (type == le_conn || type == le_pconn)) {
2649 				zend_list_addref(conn_id);
2650 				Z_LVAL_P(return_value) = conn_id;
2651 				Z_TYPE_P(return_value) = IS_RESOURCE;
2652 				efree(hashed_details);
2653 				return;
2654 			} else {
2655 				zend_hash_del(&EG(regular_list), hashed_details, hashed_len + 1);
2656 			}
2657 		}
2658 		if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
2659 			php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open connections (%ld)",ODBCG(num_links));
2660 			efree(hashed_details);
2661 			RETURN_FALSE;
2662 		}
2663 
2664 		if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0 TSRMLS_CC)) {
2665 			efree(hashed_details);
2666 			RETURN_FALSE;
2667 		}
2668 		db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_conn);
2669 		new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
2670 		Z_TYPE(new_index_ptr) = le_index_ptr;
2671 
2672 		if (zend_hash_update(&EG(regular_list), hashed_details, hashed_len + 1, (void *) &new_index_ptr,
2673 				   sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
2674 			efree(hashed_details);
2675 			RETURN_FALSE;
2676 			/* XXX Free Connection */
2677 		}
2678 		ODBCG(num_links)++;
2679 	}
2680 	efree(hashed_details);
2681 }
2682 /* }}} */
2683 
2684 /* {{{ proto void odbc_close(resource connection_id)
2685    Close an ODBC connection */
PHP_FUNCTION(odbc_close)2686 PHP_FUNCTION(odbc_close)
2687 {
2688 	zval *pv_conn;
2689 	void *ptr;
2690 	odbc_connection *conn;
2691 	odbc_result *res;
2692 	int nument;
2693 	int i;
2694 	int type;
2695 	int is_pconn = 0;
2696 	int found_resource_type = le_conn;
2697 
2698 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
2699 		return;
2700 	}
2701 
2702 	conn = (odbc_connection *) zend_fetch_resource(&pv_conn TSRMLS_CC, -1, "ODBC-Link", &found_resource_type, 2, le_conn, le_pconn);
2703 	if (found_resource_type==le_pconn) {
2704 		is_pconn = 1;
2705 	}
2706 
2707 	nument = zend_hash_next_free_element(&EG(regular_list));
2708 
2709 	for(i = 1; i < nument; i++){
2710 		ptr = zend_list_find(i, &type);
2711 		if(ptr && (type == le_result)){
2712 			res = (odbc_result *)ptr;
2713 			if(res->conn_ptr == conn){
2714 				zend_list_delete(i);
2715 			}
2716 		}
2717 	}
2718 
2719 	zend_list_delete(Z_LVAL_P(pv_conn));
2720 
2721 	if(is_pconn){
2722 		zend_hash_apply_with_argument(&EG(persistent_list),	(apply_func_arg_t) _close_pconn_with_id, (void *) &(Z_LVAL_P(pv_conn)) TSRMLS_CC);
2723 	}
2724 }
2725 /* }}} */
2726 
2727 /* {{{ proto int odbc_num_rows(resource result_id)
2728    Get number of rows in a result */
PHP_FUNCTION(odbc_num_rows)2729 PHP_FUNCTION(odbc_num_rows)
2730 {
2731 	odbc_result *result;
2732 	SQLLEN rows;
2733 	zval *pv_res;
2734 
2735 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2736 		return;
2737 	}
2738 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2739 	SQLRowCount(result->stmt, &rows);
2740 	RETURN_LONG(rows);
2741 }
2742 /* }}} */
2743 
2744 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
2745 /* {{{ proto bool odbc_next_result(resource result_id)
2746    Checks if multiple results are available */
PHP_FUNCTION(odbc_next_result)2747 PHP_FUNCTION(odbc_next_result)
2748 {
2749 	odbc_result *result;
2750 	zval *pv_res;
2751 	int rc, i;
2752 
2753 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2754 		return;
2755 	}
2756 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2757 
2758 	if (result->values) {
2759 		for(i = 0; i < result->numcols; i++) {
2760 			if (result->values[i].value) {
2761 				efree(result->values[i].value);
2762 			}
2763 		}
2764 		efree(result->values);
2765 		result->values = NULL;
2766 	}
2767 
2768 	result->fetched = 0;
2769 	rc = SQLMoreResults(result->stmt);
2770 	if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS) {
2771 		rc = SQLFreeStmt(result->stmt, SQL_UNBIND);
2772 		SQLNumParams(result->stmt, &(result->numparams));
2773 		SQLNumResultCols(result->stmt, &(result->numcols));
2774 
2775 		if (result->numcols > 0) {
2776 			if (!odbc_bindcols(result TSRMLS_CC)) {
2777 				efree(result);
2778 				RETVAL_FALSE;
2779 			}
2780 		} else {
2781 			result->values = NULL;
2782 		}
2783 		RETURN_TRUE;
2784 	} else if (rc == SQL_NO_DATA_FOUND) {
2785 		RETURN_FALSE;
2786 	} else {
2787 		odbc_sql_error(result->conn_ptr, result->stmt, "SQLMoreResults");
2788 		RETURN_FALSE;
2789 	}
2790 }
2791 /* }}} */
2792 #endif
2793 
2794 /* {{{ proto int odbc_num_fields(resource result_id)
2795    Get number of columns in a result */
PHP_FUNCTION(odbc_num_fields)2796 PHP_FUNCTION(odbc_num_fields)
2797 {
2798 	odbc_result *result;
2799 	zval *pv_res;
2800 
2801 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2802 		return;
2803 	}
2804 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2805 	RETURN_LONG(result->numcols);
2806 }
2807 /* }}} */
2808 
2809 /* {{{ proto string odbc_field_name(resource result_id, int field_number)
2810    Get a column name */
PHP_FUNCTION(odbc_field_name)2811 PHP_FUNCTION(odbc_field_name)
2812 {
2813 	odbc_result *result;
2814 	zval *pv_res;
2815 	long pv_num;
2816 
2817 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
2818 		return;
2819 	}
2820 
2821 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2822 
2823 	if (result->numcols == 0) {
2824 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2825 		RETURN_FALSE;
2826 	}
2827 
2828 	if (pv_num > result->numcols) {
2829 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
2830 		RETURN_FALSE;
2831 	}
2832 
2833 	if (pv_num < 1) {
2834 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
2835 		RETURN_FALSE;
2836 	}
2837 
2838 	RETURN_STRING(result->values[pv_num - 1].name, 1);
2839 }
2840 /* }}} */
2841 
2842 /* {{{ proto string odbc_field_type(resource result_id, int field_number)
2843    Get the datatype of a column */
PHP_FUNCTION(odbc_field_type)2844 PHP_FUNCTION(odbc_field_type)
2845 {
2846 	odbc_result	*result;
2847 	char    	tmp[32];
2848 	SQLSMALLINT	tmplen;
2849 	zval		*pv_res;
2850 	long		pv_num;
2851 
2852 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
2853 		return;
2854 	}
2855 
2856 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2857 
2858 	if (result->numcols == 0) {
2859 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2860 		RETURN_FALSE;
2861 	}
2862 
2863 	if (pv_num > result->numcols) {
2864 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
2865 		RETURN_FALSE;
2866 	}
2867 
2868 	if (pv_num < 1) {
2869 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
2870 		RETURN_FALSE;
2871 	}
2872 
2873 	SQLColAttributes(result->stmt, (SQLUSMALLINT)pv_num, SQL_COLUMN_TYPE_NAME, tmp, 31, &tmplen, NULL);
2874 	RETURN_STRING(tmp,1)
2875 }
2876 /* }}} */
2877 
2878 /* {{{ proto int odbc_field_len(resource result_id, int field_number)
2879    Get the length (precision) of a column */
PHP_FUNCTION(odbc_field_len)2880 PHP_FUNCTION(odbc_field_len)
2881 {
2882 	odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2883 }
2884 /* }}} */
2885 
2886 /* {{{ proto int odbc_field_scale(resource result_id, int field_number)
2887    Get the scale of a column */
PHP_FUNCTION(odbc_field_scale)2888 PHP_FUNCTION(odbc_field_scale)
2889 {
2890 	odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2891 }
2892 /* }}} */
2893 
2894 /* {{{ proto int odbc_field_num(resource result_id, string field_name)
2895    Return column number */
PHP_FUNCTION(odbc_field_num)2896 PHP_FUNCTION(odbc_field_num)
2897 {
2898 	char *fname;
2899 	int i, field_ind, fname_len;
2900 	odbc_result *result;
2901 	zval *pv_res;
2902 
2903 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_res, &fname, &fname_len) == FAILURE) {
2904 		return;
2905 	}
2906 
2907 	ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2908 
2909 	if (result->numcols == 0) {
2910 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2911 		RETURN_FALSE;
2912 	}
2913 
2914 	field_ind = -1;
2915 	for(i = 0; i < result->numcols; i++) {
2916 		if (strcasecmp(result->values[i].name, fname) == 0) {
2917 			field_ind = i + 1;
2918 		}
2919 	}
2920 
2921 	if (field_ind == -1) {
2922 		RETURN_FALSE;
2923 	}
2924 	RETURN_LONG(field_ind);
2925 }
2926 /* }}} */
2927 
2928 /* {{{ proto mixed odbc_autocommit(resource connection_id [, int OnOff])
2929    Toggle autocommit mode or get status */
2930 /* There can be problems with pconnections!*/
PHP_FUNCTION(odbc_autocommit)2931 PHP_FUNCTION(odbc_autocommit)
2932 {
2933 	odbc_connection *conn;
2934 	RETCODE rc;
2935 	zval *pv_conn;
2936 	long pv_onoff = 0;
2937 
2938 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_onoff) == FAILURE) {
2939 		return;
2940 	}
2941 
2942 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
2943 
2944 	if (ZEND_NUM_ARGS() > 1) {
2945 		rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (pv_onoff) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
2946 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2947 			odbc_sql_error(conn, SQL_NULL_HSTMT, "Set autocommit");
2948 			RETURN_FALSE;
2949 		}
2950 		RETVAL_TRUE;
2951 	} else {
2952 		SQLINTEGER status;
2953 
2954 		rc = SQLGetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (PTR)&status);
2955 		if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2956 			odbc_sql_error(conn, SQL_NULL_HSTMT, "Get commit status");
2957 			RETURN_FALSE;
2958 		}
2959 		RETVAL_LONG((long)status);
2960 	}
2961 }
2962 /* }}} */
2963 
2964 /* {{{ proto bool odbc_commit(resource connection_id)
2965    Commit an ODBC transaction */
PHP_FUNCTION(odbc_commit)2966 PHP_FUNCTION(odbc_commit)
2967 {
2968 	odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2969 }
2970 /* }}} */
2971 
2972 /* {{{ proto bool odbc_rollback(resource connection_id)
2973    Rollback a transaction */
PHP_FUNCTION(odbc_rollback)2974 PHP_FUNCTION(odbc_rollback)
2975 {
2976 	odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2977 }
2978 /* }}} */
2979 
2980 /* {{{ php_odbc_lasterror */
php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS,int mode)2981 static void php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS, int mode)
2982 {
2983 	odbc_connection *conn;
2984 	zval *pv_handle;
2985 	char *ptr;
2986 	int len;
2987 
2988 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &pv_handle) == FAILURE) {
2989 		return;
2990 	}
2991 
2992 	if (mode == 0) {  /* last state */
2993 		len = 6;
2994 	} else { /* last error message */
2995 		len = SQL_MAX_MESSAGE_LENGTH;
2996 	}
2997 
2998 	if (ZEND_NUM_ARGS() == 1) {
2999 		ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
3000 		ptr = ecalloc(len + 1, 1);
3001 		if (mode == 0) {
3002 			strlcpy(ptr, conn->laststate, len+1);
3003 		} else {
3004 			strlcpy(ptr, conn->lasterrormsg, len+1);
3005 		}
3006 	} else {
3007 		ptr = ecalloc(len + 1, 1);
3008 		if (mode == 0) {
3009 			strlcpy(ptr, ODBCG(laststate), len+1);
3010 		} else {
3011 			strlcpy(ptr, ODBCG(lasterrormsg), len+1);
3012 		}
3013 	}
3014 	RETVAL_STRING(ptr, 0);
3015 }
3016 /* }}} */
3017 
3018 /* {{{ proto string odbc_error([resource connection_id])
3019    Get the last error code */
PHP_FUNCTION(odbc_error)3020 PHP_FUNCTION(odbc_error)
3021 {
3022 	php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3023 }
3024 /* }}} */
3025 
3026 /* {{{ proto string odbc_errormsg([resource connection_id])
3027    Get the last error message */
PHP_FUNCTION(odbc_errormsg)3028 PHP_FUNCTION(odbc_errormsg)
3029 {
3030 	php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3031 }
3032 /* }}} */
3033 
3034 /* {{{ proto bool odbc_setoption(resource conn_id|result_id, int which, int option, int value)
3035    Sets connection or statement options */
3036 /* This one has to be used carefully. We can't allow to set connection options for
3037    persistent connections. I think that SetStmtOption is of little use, since most
3038    of those can only be specified before preparing/executing statements.
3039    On the other hand, they can be made connection wide default through SetConnectOption
3040    - but will be overidden by calls to SetStmtOption() in odbc_prepare/odbc_do
3041 */
PHP_FUNCTION(odbc_setoption)3042 PHP_FUNCTION(odbc_setoption)
3043 {
3044 	odbc_connection *conn;
3045 	odbc_result	*result;
3046 	RETCODE rc;
3047 	zval *pv_handle;
3048 	long pv_which, pv_opt, pv_val;
3049 
3050 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) {
3051 		return;
3052 	}
3053 
3054 	switch (pv_which) {
3055 		case 1:		/* SQLSetConnectOption */
3056 			ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
3057 
3058 			if (conn->persistent) {
3059 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set option for persistent connection");
3060 				RETURN_FALSE;
3061 			}
3062 			rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val);
3063 			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
3064 				odbc_sql_error(conn, SQL_NULL_HSTMT, "SetConnectOption");
3065 				RETURN_FALSE;
3066 			}
3067 			break;
3068 		case 2:		/* SQLSetStmtOption */
3069 			ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_handle, -1, "ODBC result", le_result);
3070 
3071 			rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val);
3072 
3073 			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
3074 				odbc_sql_error(result->conn_ptr, result->stmt, "SetStmtOption");
3075 				RETURN_FALSE;
3076 			}
3077 			break;
3078 		default:
3079 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option type");
3080 			RETURN_FALSE;
3081 			break;
3082 	}
3083 
3084 	RETURN_TRUE;
3085 }
3086 /* }}} */
3087 
3088 /*
3089  * metadata functions
3090  */
3091 
3092 /* {{{ proto resource odbc_tables(resource connection_id [, string qualifier [, string owner [, string name [, string table_types]]]])
3093    Call the SQLTables function */
PHP_FUNCTION(odbc_tables)3094 PHP_FUNCTION(odbc_tables)
3095 {
3096 	zval *pv_conn;
3097 	odbc_result   *result = NULL;
3098 	odbc_connection *conn;
3099 	char *cat = NULL, *schema = NULL, *table = NULL, *type = NULL;
3100 	int cat_len = 0, schema_len = 0, table_len = 0, type_len = 0;
3101 	RETCODE rc;
3102 
3103 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3104 		&table, &table_len, &type, &type_len) == FAILURE) {
3105 		return;
3106 	}
3107 
3108 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3109 
3110 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3111 
3112 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3113 	if (rc == SQL_INVALID_HANDLE) {
3114 		efree(result);
3115 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3116 		RETURN_FALSE;
3117 	}
3118 
3119 	if (rc == SQL_ERROR) {
3120 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3121 		efree(result);
3122 		RETURN_FALSE;
3123 	}
3124 
3125 	/* This hack is needed to access table information in Access databases (fmk) */
3126 	if (table && table_len && schema && schema_len == 0) {
3127 		schema = NULL;
3128 	}
3129 
3130 	rc = SQLTables(result->stmt,
3131 			cat, SAFE_SQL_NTS(cat),
3132 			schema,	SAFE_SQL_NTS(schema),
3133 			table, SAFE_SQL_NTS(table),
3134 			type, SAFE_SQL_NTS(type));
3135 
3136 	if (rc == SQL_ERROR) {
3137 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTables");
3138 		efree(result);
3139 		RETURN_FALSE;
3140 	}
3141 
3142 	result->numparams = 0;
3143 	SQLNumResultCols(result->stmt, &(result->numcols));
3144 
3145 	if (result->numcols > 0) {
3146 		if (!odbc_bindcols(result TSRMLS_CC)) {
3147 			efree(result);
3148 			RETURN_FALSE;
3149 		}
3150 	} else {
3151 		result->values = NULL;
3152 	}
3153 	result->conn_ptr = conn;
3154 	result->fetched = 0;
3155 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3156 }
3157 /* }}} */
3158 
3159 /* {{{ proto resource odbc_columns(resource connection_id [, string qualifier [, string owner [, string table_name [, string column_name]]]])
3160    Returns a result identifier that can be used to fetch a list of column names in specified tables */
PHP_FUNCTION(odbc_columns)3161 PHP_FUNCTION(odbc_columns)
3162 {
3163 	zval *pv_conn;
3164 	odbc_result *result = NULL;
3165 	odbc_connection *conn;
3166 	char *cat = NULL, *schema = NULL, *table = NULL, *column = NULL;
3167 	int cat_len = 0, schema_len = 0, table_len = 0, column_len = 0;
3168 	RETCODE rc;
3169 
3170 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3171 		&table, &table_len, &column, &column_len) == FAILURE) {
3172 		return;
3173 	}
3174 
3175 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3176 
3177 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3178 
3179 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3180 	if (rc == SQL_INVALID_HANDLE) {
3181 		efree(result);
3182 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3183 		RETURN_FALSE;
3184 	}
3185 
3186 	if (rc == SQL_ERROR) {
3187 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3188 		efree(result);
3189 		RETURN_FALSE;
3190 	}
3191 
3192 	/*
3193 	 * Needed to make MS Access happy
3194 	 */
3195 	if (table && table_len && schema && schema_len == 0) {
3196 		schema = NULL;
3197 	}
3198 
3199 	rc = SQLColumns(result->stmt,
3200 			cat, (SQLSMALLINT) cat_len,
3201 			schema, (SQLSMALLINT) schema_len,
3202 			table, (SQLSMALLINT) table_len,
3203 			column, (SQLSMALLINT) column_len);
3204 
3205 	if (rc == SQL_ERROR) {
3206 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumns");
3207 		efree(result);
3208 		RETURN_FALSE;
3209 	}
3210 
3211 	result->numparams = 0;
3212 	SQLNumResultCols(result->stmt, &(result->numcols));
3213 
3214 	if (result->numcols > 0) {
3215 		if (!odbc_bindcols(result TSRMLS_CC)) {
3216 			efree(result);
3217 			RETURN_FALSE;
3218 		}
3219 	} else {
3220 		result->values = NULL;
3221 	}
3222 	result->conn_ptr = conn;
3223 	result->fetched = 0;
3224 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3225 }
3226 /* }}} */
3227 
3228 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3229 /* {{{ proto resource odbc_columnprivileges(resource connection_id, string catalog, string schema, string table, string column)
3230    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)3231 PHP_FUNCTION(odbc_columnprivileges)
3232 {
3233 	zval *pv_conn;
3234 	odbc_result *result = NULL;
3235 	odbc_connection *conn;
3236 	char *cat = NULL, *schema, *table, *column;
3237 	int cat_len = 0, schema_len, table_len, column_len;
3238 	RETCODE rc;
3239 
3240 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3241 		&table, &table_len, &column, &column_len) == FAILURE) {
3242 		return;
3243 	}
3244 
3245 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3246 
3247 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3248 
3249 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3250 	if (rc == SQL_INVALID_HANDLE) {
3251 		efree(result);
3252 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3253 		RETURN_FALSE;
3254 	}
3255 
3256 	if (rc == SQL_ERROR) {
3257 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3258 		efree(result);
3259 		RETURN_FALSE;
3260 	}
3261 
3262 	rc = SQLColumnPrivileges(result->stmt,
3263 			cat, SAFE_SQL_NTS(cat),
3264 			schema, SAFE_SQL_NTS(schema),
3265 			table, SAFE_SQL_NTS(table),
3266 			column, SAFE_SQL_NTS(column));
3267 
3268 	if (rc == SQL_ERROR) {
3269 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumnPrivileges");
3270 		efree(result);
3271 		RETURN_FALSE;
3272 	}
3273 
3274 	result->numparams = 0;
3275 	SQLNumResultCols(result->stmt, &(result->numcols));
3276 
3277 	if (result->numcols > 0) {
3278 		if (!odbc_bindcols(result TSRMLS_CC)) {
3279 			efree(result);
3280 			RETURN_FALSE;
3281 		}
3282 	} else {
3283 		result->values = NULL;
3284 	}
3285 	result->conn_ptr = conn;
3286 	result->fetched = 0;
3287 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3288 }
3289 /* }}} */
3290 #endif /* HAVE_DBMAKER || HAVE_SOLID*/
3291 
3292 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
3293 /* {{{ 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)
3294    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)3295 PHP_FUNCTION(odbc_foreignkeys)
3296 {
3297 	zval *pv_conn;
3298 	odbc_result *result = NULL;
3299 	odbc_connection *conn;
3300 	char *pcat = NULL, *pschema, *ptable, *fcat, *fschema, *ftable;
3301 	int pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len;
3302 	RETCODE rc;
3303 
3304 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sssss", &pv_conn, &pcat, &pcat_len, &pschema, &pschema_len,
3305 		&ptable, &ptable_len, &fcat, &fcat_len, &fschema, &fschema_len, &ftable, &ftable_len) == FAILURE) {
3306 		return;
3307 	}
3308 
3309 #if defined(HAVE_DBMAKER) || defined(HAVE_IBMDB2)
3310 #define EMPTY_TO_NULL(xstr) \
3311 	if ((int)strlen((xstr)) == 0) (xstr) = NULL
3312 
3313 		EMPTY_TO_NULL(pcat);
3314 		EMPTY_TO_NULL(pschema);
3315 		EMPTY_TO_NULL(ptable);
3316 		EMPTY_TO_NULL(fcat);
3317 		EMPTY_TO_NULL(fschema);
3318 		EMPTY_TO_NULL(ftable);
3319 #endif
3320 
3321 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3322 
3323 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3324 
3325 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3326 	if (rc == SQL_INVALID_HANDLE) {
3327 		efree(result);
3328 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3329 		RETURN_FALSE;
3330 	}
3331 
3332 	if (rc == SQL_ERROR) {
3333 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3334 		efree(result);
3335 		RETURN_FALSE;
3336 	}
3337 
3338 	rc = SQLForeignKeys(result->stmt,
3339 			pcat, SAFE_SQL_NTS(pcat),
3340 			pschema, SAFE_SQL_NTS(pschema),
3341 			ptable, SAFE_SQL_NTS(ptable),
3342 			fcat, SAFE_SQL_NTS(fcat),
3343 			fschema, SAFE_SQL_NTS(fschema),
3344 			ftable, SAFE_SQL_NTS(ftable) );
3345 
3346 	if (rc == SQL_ERROR) {
3347 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLForeignKeys");
3348 		efree(result);
3349 		RETURN_FALSE;
3350 	}
3351 
3352 	result->numparams = 0;
3353 	SQLNumResultCols(result->stmt, &(result->numcols));
3354 
3355 	if (result->numcols > 0) {
3356 		if (!odbc_bindcols(result TSRMLS_CC)) {
3357 			efree(result);
3358 			RETURN_FALSE;
3359 		}
3360 	} else {
3361 		result->values = NULL;
3362 	}
3363 	result->conn_ptr = conn;
3364 	result->fetched = 0;
3365 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3366 }
3367 /* }}} */
3368 #endif /* HAVE_SOLID */
3369 
3370 /* {{{ proto resource odbc_gettypeinfo(resource connection_id [, int data_type])
3371    Returns a result identifier containing information about data types supported by the data source */
PHP_FUNCTION(odbc_gettypeinfo)3372 PHP_FUNCTION(odbc_gettypeinfo)
3373 {
3374 	zval *pv_conn;
3375 	long pv_data_type = SQL_ALL_TYPES;
3376 	odbc_result *result = NULL;
3377 	odbc_connection *conn;
3378 	RETCODE rc;
3379 	SQLSMALLINT data_type;
3380 
3381 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_data_type) == FAILURE) {
3382 		return;
3383 	}
3384 
3385 	data_type = (SQLSMALLINT) pv_data_type;
3386 
3387 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3388 
3389 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3390 
3391 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3392 	if (rc == SQL_INVALID_HANDLE) {
3393 		efree(result);
3394 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3395 		RETURN_FALSE;
3396 	}
3397 
3398 	if (rc == SQL_ERROR) {
3399 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3400 		efree(result);
3401 		RETURN_FALSE;
3402 	}
3403 
3404 	rc = SQLGetTypeInfo(result->stmt, data_type );
3405 
3406 	if (rc == SQL_ERROR) {
3407 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLGetTypeInfo");
3408 		efree(result);
3409 		RETURN_FALSE;
3410 	}
3411 
3412 	result->numparams = 0;
3413 	SQLNumResultCols(result->stmt, &(result->numcols));
3414 
3415 	if (result->numcols > 0) {
3416 		if (!odbc_bindcols(result TSRMLS_CC)) {
3417 			efree(result);
3418 			RETURN_FALSE;
3419 		}
3420 	} else {
3421 		result->values = NULL;
3422 	}
3423 	result->conn_ptr = conn;
3424 	result->fetched = 0;
3425 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3426 }
3427 /* }}} */
3428 
3429 /* {{{ proto resource odbc_primarykeys(resource connection_id, string qualifier, string owner, string table)
3430    Returns a result identifier listing the column names that comprise the primary key for a table */
PHP_FUNCTION(odbc_primarykeys)3431 PHP_FUNCTION(odbc_primarykeys)
3432 {
3433 	zval *pv_conn;
3434 	odbc_result   *result = NULL;
3435 	odbc_connection *conn;
3436 	char *cat = NULL, *schema = NULL, *table = NULL;
3437 	int cat_len = 0, schema_len, table_len;
3438 	RETCODE rc;
3439 
3440 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
3441 		return;
3442 	}
3443 
3444 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3445 
3446 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3447 
3448 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3449 	if (rc == SQL_INVALID_HANDLE) {
3450 		efree(result);
3451 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3452 		RETURN_FALSE;
3453 	}
3454 
3455 	if (rc == SQL_ERROR) {
3456 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3457 		efree(result);
3458 		RETURN_FALSE;
3459 	}
3460 
3461 	rc = SQLPrimaryKeys(result->stmt,
3462 			cat, SAFE_SQL_NTS(cat),
3463 			schema, SAFE_SQL_NTS(schema),
3464 			table, SAFE_SQL_NTS(table) );
3465 
3466 	if (rc == SQL_ERROR) {
3467 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLPrimaryKeys");
3468 		efree(result);
3469 		RETURN_FALSE;
3470 	}
3471 
3472 	result->numparams = 0;
3473 	SQLNumResultCols(result->stmt, &(result->numcols));
3474 
3475 	if (result->numcols > 0) {
3476 		if (!odbc_bindcols(result TSRMLS_CC)) {
3477 			efree(result);
3478 			RETURN_FALSE;
3479 		}
3480 	} else {
3481 		result->values = NULL;
3482 	}
3483 	result->conn_ptr = conn;
3484 	result->fetched = 0;
3485 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3486 }
3487 /* }}} */
3488 
3489 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3490 /* {{{ proto resource odbc_procedurecolumns(resource connection_id [, string qualifier, string owner, string proc, string column])
3491    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)3492 PHP_FUNCTION(odbc_procedurecolumns)
3493 {
3494 	zval *pv_conn;
3495 	odbc_result *result = NULL;
3496 	odbc_connection *conn;
3497 	char *cat = NULL, *schema = NULL, *proc = NULL, *col = NULL;
3498 	int cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0;
3499 	RETCODE rc;
3500 
3501 	if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 5) {
3502 		WRONG_PARAM_COUNT;
3503 	}
3504 
3505 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3506 		&proc, &proc_len, &col, &col_len) == FAILURE) {
3507 		return;
3508 	}
3509 
3510 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3511 
3512 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3513 
3514 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3515 	if (rc == SQL_INVALID_HANDLE) {
3516 		efree(result);
3517 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3518 		RETURN_FALSE;
3519 	}
3520 
3521 	if (rc == SQL_ERROR) {
3522 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3523 		efree(result);
3524 		RETURN_FALSE;
3525 	}
3526 
3527 	rc = SQLProcedureColumns(result->stmt,
3528 			cat, SAFE_SQL_NTS(cat),
3529 			schema, SAFE_SQL_NTS(schema),
3530 			proc, SAFE_SQL_NTS(proc),
3531 			col, SAFE_SQL_NTS(col) );
3532 
3533 	if (rc == SQL_ERROR) {
3534 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedureColumns");
3535 		efree(result);
3536 		RETURN_FALSE;
3537 	}
3538 
3539 	result->numparams = 0;
3540 	SQLNumResultCols(result->stmt, &(result->numcols));
3541 
3542 	if (result->numcols > 0) {
3543 		if (!odbc_bindcols(result TSRMLS_CC)) {
3544 			efree(result);
3545 			RETURN_FALSE;
3546 		}
3547 	} else {
3548 		result->values = NULL;
3549 	}
3550 	result->conn_ptr = conn;
3551 	result->fetched = 0;
3552 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3553 }
3554 /* }}} */
3555 #endif /* HAVE_SOLID */
3556 
3557 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
3558 /* {{{ proto resource odbc_procedures(resource connection_id [, string qualifier, string owner, string name])
3559    Returns a result identifier containg the list of procedure names in a datasource */
PHP_FUNCTION(odbc_procedures)3560 PHP_FUNCTION(odbc_procedures)
3561 {
3562 	zval *pv_conn;
3563 	odbc_result   *result = NULL;
3564 	odbc_connection *conn;
3565 	char *cat = NULL, *schema = NULL, *proc = NULL;
3566 	int cat_len = 0, schema_len = 0, proc_len = 0;
3567 	RETCODE rc;
3568 
3569 	if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 4) {
3570 		WRONG_PARAM_COUNT;
3571 	}
3572 
3573 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) {
3574 		return;
3575 	}
3576 
3577 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3578 
3579 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3580 
3581 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3582 	if (rc == SQL_INVALID_HANDLE) {
3583 		efree(result);
3584 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3585 		RETURN_FALSE;
3586 	}
3587 
3588 	if (rc == SQL_ERROR) {
3589 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3590 		efree(result);
3591 		RETURN_FALSE;
3592 	}
3593 
3594 	rc = SQLProcedures(result->stmt,
3595 			cat, SAFE_SQL_NTS(cat),
3596 			schema, SAFE_SQL_NTS(schema),
3597 			proc, SAFE_SQL_NTS(proc) );
3598 
3599 	if (rc == SQL_ERROR) {
3600 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedures");
3601 		efree(result);
3602 		RETURN_FALSE;
3603 	}
3604 
3605 	result->numparams = 0;
3606 	SQLNumResultCols(result->stmt, &(result->numcols));
3607 
3608 	if (result->numcols > 0) {
3609 		if (!odbc_bindcols(result TSRMLS_CC)) {
3610 			efree(result);
3611 			RETURN_FALSE;
3612 		}
3613 	} else {
3614 		result->values = NULL;
3615 	}
3616 	result->conn_ptr = conn;
3617 	result->fetched = 0;
3618 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3619 }
3620 /* }}} */
3621 #endif /* HAVE_SOLID */
3622 
3623 /* {{{ proto resource odbc_specialcolumns(resource connection_id, int type, string qualifier, string owner, string table, int scope, int nullable)
3624    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)3625 PHP_FUNCTION(odbc_specialcolumns)
3626 {
3627 	zval *pv_conn;
3628 	long vtype, vscope, vnullable;
3629 	odbc_result *result = NULL;
3630 	odbc_connection *conn;
3631 	char *cat = NULL, *schema = NULL, *name = NULL;
3632 	int cat_len = 0, schema_len, name_len;
3633 	SQLUSMALLINT type, scope, nullable;
3634 	RETCODE rc;
3635 
3636 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rls!ssll", &pv_conn, &vtype, &cat, &cat_len, &schema, &schema_len,
3637 		&name, &name_len, &vscope, &vnullable) == FAILURE) {
3638 		return;
3639 	}
3640 
3641 	type = (SQLUSMALLINT) vtype;
3642 	scope = (SQLUSMALLINT) vscope;
3643 	nullable = (SQLUSMALLINT) vnullable;
3644 
3645 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3646 
3647 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3648 
3649 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3650 	if (rc == SQL_INVALID_HANDLE) {
3651 		efree(result);
3652 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3653 		RETURN_FALSE;
3654 	}
3655 
3656 	if (rc == SQL_ERROR) {
3657 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3658 		efree(result);
3659 		RETURN_FALSE;
3660 	}
3661 
3662 	rc = SQLSpecialColumns(result->stmt,
3663 			type,
3664 			cat, SAFE_SQL_NTS(cat),
3665 			schema, SAFE_SQL_NTS(schema),
3666 			name, SAFE_SQL_NTS(name),
3667 			scope,
3668 			nullable);
3669 
3670 	if (rc == SQL_ERROR) {
3671 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLSpecialColumns");
3672 		efree(result);
3673 		RETURN_FALSE;
3674 	}
3675 
3676 	result->numparams = 0;
3677 	SQLNumResultCols(result->stmt, &(result->numcols));
3678 
3679 	if (result->numcols > 0) {
3680 		if (!odbc_bindcols(result TSRMLS_CC)) {
3681 			efree(result);
3682 			RETURN_FALSE;
3683 		}
3684 	} else {
3685 		result->values = NULL;
3686 	}
3687 	result->conn_ptr = conn;
3688 	result->fetched = 0;
3689 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3690 }
3691 /* }}} */
3692 
3693 /* {{{ proto resource odbc_statistics(resource connection_id, string qualifier, string owner, string name, int unique, int accuracy)
3694    Returns a result identifier that contains statistics about a single table and the indexes associated with the table */
PHP_FUNCTION(odbc_statistics)3695 PHP_FUNCTION(odbc_statistics)
3696 {
3697 	zval *pv_conn;
3698 	long vunique, vreserved;
3699 	odbc_result *result = NULL;
3700 	odbc_connection *conn;
3701 	char *cat = NULL, *schema, *name;
3702 	int cat_len = 0, schema_len, name_len;
3703 	SQLUSMALLINT unique, reserved;
3704 	RETCODE rc;
3705 
3706 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ssll", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3707 		&name, &name_len, &vunique, &vreserved) == FAILURE) {
3708 		return;
3709 	}
3710 
3711 	unique = (SQLUSMALLINT) vunique;
3712 	reserved = (SQLUSMALLINT) vreserved;
3713 
3714 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3715 
3716 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3717 
3718 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3719 	if (rc == SQL_INVALID_HANDLE) {
3720 		efree(result);
3721 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3722 		RETURN_FALSE;
3723 	}
3724 
3725 	if (rc == SQL_ERROR) {
3726 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3727 		efree(result);
3728 		RETURN_FALSE;
3729 	}
3730 
3731 	rc = SQLStatistics(result->stmt,
3732 			cat, SAFE_SQL_NTS(cat),
3733 			schema, SAFE_SQL_NTS(schema),
3734 			name, SAFE_SQL_NTS(name),
3735 			unique,
3736 			reserved);
3737 
3738 	if (rc == SQL_ERROR) {
3739 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLStatistics");
3740 		efree(result);
3741 		RETURN_FALSE;
3742 	}
3743 
3744 	result->numparams = 0;
3745 	SQLNumResultCols(result->stmt, &(result->numcols));
3746 
3747 	if (result->numcols > 0) {
3748 		if (!odbc_bindcols(result TSRMLS_CC)) {
3749 			efree(result);
3750 			RETURN_FALSE;
3751 		}
3752 	} else {
3753 		result->values = NULL;
3754 	}
3755 	result->conn_ptr = conn;
3756 	result->fetched = 0;
3757 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3758 }
3759 /* }}} */
3760 
3761 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3762 /* {{{ proto resource odbc_tableprivileges(resource connection_id, string qualifier, string owner, string name)
3763    Returns a result identifier containing a list of tables and the privileges associated with each table */
PHP_FUNCTION(odbc_tableprivileges)3764 PHP_FUNCTION(odbc_tableprivileges)
3765 {
3766 	zval *pv_conn;
3767 	odbc_result   *result = NULL;
3768 	odbc_connection *conn;
3769 	char *cat = NULL, *schema = NULL, *table = NULL;
3770 	int cat_len = 0, schema_len, table_len;
3771 	RETCODE rc;
3772 
3773 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
3774 		return;
3775 	}
3776 
3777 	ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3778 
3779 	result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3780 
3781 	rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
3782 	if (rc == SQL_INVALID_HANDLE) {
3783 		efree(result);
3784 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3785 		RETURN_FALSE;
3786 	}
3787 
3788 	if (rc == SQL_ERROR) {
3789 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3790 		efree(result);
3791 		RETURN_FALSE;
3792 	}
3793 
3794 	rc = SQLTablePrivileges(result->stmt,
3795 			cat, SAFE_SQL_NTS(cat),
3796 			schema, SAFE_SQL_NTS(schema),
3797 			table, SAFE_SQL_NTS(table));
3798 
3799 	if (rc == SQL_ERROR) {
3800 		odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTablePrivileges");
3801 		efree(result);
3802 		RETURN_FALSE;
3803 	}
3804 
3805 	result->numparams = 0;
3806 	SQLNumResultCols(result->stmt, &(result->numcols));
3807 
3808 	if (result->numcols > 0) {
3809 		if (!odbc_bindcols(result TSRMLS_CC)) {
3810 			efree(result);
3811 			RETURN_FALSE;
3812 		}
3813 	} else {
3814 		result->values = NULL;
3815 	}
3816 	result->conn_ptr = conn;
3817 	result->fetched = 0;
3818 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3819 }
3820 /* }}} */
3821 #endif /* HAVE_DBMAKER */
3822 
3823 #endif /* HAVE_UODBC */
3824 
3825 /*
3826  * Local variables:
3827  * tab-width: 4
3828  * c-basic-offset: 4
3829  * End:
3830  * vim600: sw=4 ts=4 fdm=marker
3831  * vim<600: sw=4 ts=4
3832  */
3833