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