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