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