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