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