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