You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3526 lines
97 KiB

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