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