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