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