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.

1216 lines
36 KiB

20 years ago
27 years ago
27 years ago
23 years ago
27 years ago
27 years ago
23 years ago
23 years ago
23 years ago
27 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
23 years ago
23 years ago
23 years ago
20 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2007 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.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: Jouni Ahto <jouni.ahto@exdec.fi> |
  16. | Andrew Avdeev <andy@rsc.mv.ru> |
  17. | Ard Biesheuvel <a.k.biesheuvel@ewi.tudelft.nl> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #define _GNU_SOURCE
  25. #include "php.h"
  26. #if HAVE_IBASE
  27. #include "php_ini.h"
  28. #include "ext/standard/php_standard.h"
  29. #include "ext/standard/md5.h"
  30. #include "php_interbase.h"
  31. #include "php_ibase_includes.h"
  32. #include "SAPI.h"
  33. #include <time.h>
  34. #define ROLLBACK 0
  35. #define COMMIT 1
  36. #define RETAIN 2
  37. ZEND_DECLARE_MODULE_GLOBALS(ibase)
  38. static PHP_GINIT_FUNCTION(ibase);
  39. /* {{{ extension definition structures */
  40. const zend_function_entry ibase_functions[] = {
  41. PHP_FE(ibase_connect, NULL)
  42. PHP_FE(ibase_pconnect, NULL)
  43. PHP_FE(ibase_close, NULL)
  44. PHP_FE(ibase_drop_db, NULL)
  45. PHP_FE(ibase_query, NULL)
  46. PHP_FE(ibase_fetch_row, NULL)
  47. PHP_FE(ibase_fetch_assoc, NULL)
  48. PHP_FE(ibase_fetch_object, NULL)
  49. PHP_FE(ibase_free_result, NULL)
  50. PHP_FE(ibase_name_result, NULL)
  51. PHP_FE(ibase_prepare, NULL)
  52. PHP_FE(ibase_execute, NULL)
  53. PHP_FE(ibase_free_query, NULL)
  54. PHP_FE(ibase_gen_id, NULL)
  55. PHP_FE(ibase_num_fields, NULL)
  56. PHP_FE(ibase_num_params, NULL)
  57. #if abies_0
  58. PHP_FE(ibase_num_rows, NULL)
  59. #endif
  60. PHP_FE(ibase_affected_rows, NULL)
  61. PHP_FE(ibase_field_info, NULL)
  62. PHP_FE(ibase_param_info, NULL)
  63. PHP_FE(ibase_trans, NULL)
  64. PHP_FE(ibase_commit, NULL)
  65. PHP_FE(ibase_rollback, NULL)
  66. PHP_FE(ibase_commit_ret, NULL)
  67. PHP_FE(ibase_rollback_ret, NULL)
  68. PHP_FE(ibase_blob_info, NULL)
  69. PHP_FE(ibase_blob_create, NULL)
  70. PHP_FE(ibase_blob_add, NULL)
  71. PHP_FE(ibase_blob_cancel, NULL)
  72. PHP_FE(ibase_blob_close, NULL)
  73. PHP_FE(ibase_blob_open, NULL)
  74. PHP_FE(ibase_blob_get, NULL)
  75. PHP_FE(ibase_blob_echo, NULL)
  76. PHP_FE(ibase_blob_import, NULL)
  77. PHP_FE(ibase_errmsg, NULL)
  78. PHP_FE(ibase_errcode, NULL)
  79. PHP_FE(ibase_add_user, NULL)
  80. PHP_FE(ibase_modify_user, NULL)
  81. PHP_FE(ibase_delete_user, NULL)
  82. PHP_FE(ibase_service_attach, NULL)
  83. PHP_FE(ibase_service_detach, NULL)
  84. PHP_FE(ibase_backup, NULL)
  85. PHP_FE(ibase_restore, NULL)
  86. PHP_FE(ibase_maintain_db, NULL)
  87. PHP_FE(ibase_db_info, NULL)
  88. PHP_FE(ibase_server_info, NULL)
  89. PHP_FE(ibase_wait_event, NULL)
  90. PHP_FE(ibase_set_event_handler, NULL)
  91. PHP_FE(ibase_free_event_handler, NULL)
  92. /**
  93. * These aliases are provided in order to maintain forward compatibility. As Firebird
  94. * and InterBase are developed independently, functionality might be different between
  95. * the two branches in future versions.
  96. * Firebird users should use the aliases, so future InterBase-specific changes will
  97. * not affect their code
  98. */
  99. PHP_FALIAS(fbird_connect,ibase_connect, NULL)
  100. PHP_FALIAS(fbird_pconnect,ibase_pconnect, NULL)
  101. PHP_FALIAS(fbird_close,ibase_close, NULL)
  102. PHP_FALIAS(fbird_drop_db,ibase_drop_db, NULL)
  103. PHP_FALIAS(fbird_query,ibase_query, NULL)
  104. PHP_FALIAS(fbird_fetch_row,ibase_fetch_row, NULL)
  105. PHP_FALIAS(fbird_fetch_assoc,ibase_fetch_assoc, NULL)
  106. PHP_FALIAS(fbird_fetch_object,ibase_fetch_object, NULL)
  107. PHP_FALIAS(fbird_free_result,ibase_free_result, NULL)
  108. PHP_FALIAS(fbird_name_result,ibase_name_result, NULL)
  109. PHP_FALIAS(fbird_prepare,ibase_prepare, NULL)
  110. PHP_FALIAS(fbird_execute,ibase_execute, NULL)
  111. PHP_FALIAS(fbird_free_query,ibase_free_query, NULL)
  112. PHP_FALIAS(fbird_gen_id,ibase_gen_id, NULL)
  113. PHP_FALIAS(fbird_num_fields,ibase_num_fields, NULL)
  114. PHP_FALIAS(fbird_num_params,ibase_num_params, NULL)
  115. #if abies_0
  116. PHP_FALIAS(fbird_num_rows,ibase_num_rows, NULL)
  117. #endif
  118. PHP_FALIAS(fbird_affected_rows,ibase_affected_rows, NULL)
  119. PHP_FALIAS(fbird_field_info,ibase_field_info, NULL)
  120. PHP_FALIAS(fbird_param_info,ibase_param_info, NULL)
  121. PHP_FALIAS(fbird_trans,ibase_trans, NULL)
  122. PHP_FALIAS(fbird_commit,ibase_commit, NULL)
  123. PHP_FALIAS(fbird_rollback,ibase_rollback, NULL)
  124. PHP_FALIAS(fbird_commit_ret,ibase_commit_ret, NULL)
  125. PHP_FALIAS(fbird_rollback_ret,ibase_rollback_ret, NULL)
  126. PHP_FALIAS(fbird_blob_info,ibase_blob_info, NULL)
  127. PHP_FALIAS(fbird_blob_create,ibase_blob_create, NULL)
  128. PHP_FALIAS(fbird_blob_add,ibase_blob_add, NULL)
  129. PHP_FALIAS(fbird_blob_cancel,ibase_blob_cancel, NULL)
  130. PHP_FALIAS(fbird_blob_close,ibase_blob_close, NULL)
  131. PHP_FALIAS(fbird_blob_open,ibase_blob_open, NULL)
  132. PHP_FALIAS(fbird_blob_get,ibase_blob_get, NULL)
  133. PHP_FALIAS(fbird_blob_echo,ibase_blob_echo, NULL)
  134. PHP_FALIAS(fbird_blob_import,ibase_blob_import, NULL)
  135. PHP_FALIAS(fbird_errmsg,ibase_errmsg, NULL)
  136. PHP_FALIAS(fbird_errcode,ibase_errcode, NULL)
  137. PHP_FALIAS(fbird_add_user,ibase_add_user, NULL)
  138. PHP_FALIAS(fbird_modify_user,ibase_modify_user, NULL)
  139. PHP_FALIAS(fbird_delete_user,ibase_delete_user, NULL)
  140. PHP_FALIAS(fbird_service_attach,ibase_service_attach, NULL)
  141. PHP_FALIAS(fbird_service_detach,ibase_service_detach, NULL)
  142. PHP_FALIAS(fbird_backup,ibase_backup, NULL)
  143. PHP_FALIAS(fbird_restore,ibase_restore, NULL)
  144. PHP_FALIAS(fbird_maintain_db,ibase_maintain_db, NULL)
  145. PHP_FALIAS(fbird_db_info,ibase_db_info, NULL)
  146. PHP_FALIAS(fbird_server_info,ibase_server_info, NULL)
  147. PHP_FALIAS(fbird_wait_event,ibase_wait_event, NULL)
  148. PHP_FALIAS(fbird_set_event_handler,ibase_set_event_handler, NULL)
  149. PHP_FALIAS(fbird_free_event_handler,ibase_free_event_handler, NULL)
  150. {NULL, NULL, NULL}
  151. };
  152. zend_module_entry ibase_module_entry = {
  153. STANDARD_MODULE_HEADER,
  154. "interbase",
  155. ibase_functions,
  156. PHP_MINIT(ibase),
  157. PHP_MSHUTDOWN(ibase),
  158. NULL,
  159. PHP_RSHUTDOWN(ibase),
  160. PHP_MINFO(ibase),
  161. NO_VERSION_YET,
  162. PHP_MODULE_GLOBALS(ibase),
  163. PHP_GINIT(ibase),
  164. NULL,
  165. NULL,
  166. STANDARD_MODULE_PROPERTIES_EX
  167. };
  168. #ifdef COMPILE_DL_INTERBASE
  169. ZEND_GET_MODULE(ibase)
  170. #endif
  171. /* True globals, no need for thread safety */
  172. int le_link, le_plink, le_trans;
  173. /* }}} */
  174. /* error handling ---------------------------- */
  175. /* {{{ proto string ibase_errmsg(void)
  176. Return error message */
  177. PHP_FUNCTION(ibase_errmsg)
  178. {
  179. if (ZEND_NUM_ARGS() != 0) {
  180. WRONG_PARAM_COUNT;
  181. }
  182. if (IBG(sql_code) != 0) {
  183. RETURN_STRING(IBG(errmsg), 1);
  184. }
  185. RETURN_FALSE;
  186. }
  187. /* }}} */
  188. /* {{{ proto int ibase_errcode(void)
  189. Return error code */
  190. PHP_FUNCTION(ibase_errcode)
  191. {
  192. if (ZEND_NUM_ARGS() != 0) {
  193. WRONG_PARAM_COUNT;
  194. }
  195. if (IBG(sql_code) != 0) {
  196. RETURN_LONG(IBG(sql_code));
  197. }
  198. RETURN_FALSE;
  199. }
  200. /* }}} */
  201. /* print interbase error and save it for ibase_errmsg() */
  202. void _php_ibase_error(TSRMLS_D) /* {{{ */
  203. {
  204. char *s = IBG(errmsg);
  205. ISC_STATUS *statusp = IB_STATUS;
  206. IBG(sql_code) = isc_sqlcode(IB_STATUS);
  207. while ((s - IBG(errmsg)) < MAX_ERRMSG - (IBASE_MSGSIZE + 2) && isc_interprete(s, &statusp)) {
  208. strcat(IBG(errmsg), " ");
  209. s = IBG(errmsg) + strlen(IBG(errmsg));
  210. }
  211. php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
  212. }
  213. /* }}} */
  214. /* print php interbase module error and save it for ibase_errmsg() */
  215. void _php_ibase_module_error(char *msg TSRMLS_DC, ...) /* {{{ */
  216. {
  217. va_list ap;
  218. #ifdef ZTS
  219. va_start(ap, TSRMLS_C);
  220. #else
  221. va_start(ap, msg);
  222. #endif
  223. /* vsnprintf NUL terminates the buf and writes at most n-1 chars+NUL */
  224. vsnprintf(IBG(errmsg), MAX_ERRMSG, msg, ap);
  225. va_end(ap);
  226. IBG(sql_code) = -999; /* no SQL error */
  227. php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
  228. }
  229. /* }}} */
  230. /* {{{ internal macros, functions and structures */
  231. typedef struct {
  232. isc_db_handle *db_ptr;
  233. long tpb_len;
  234. char *tpb_ptr;
  235. } ISC_TEB;
  236. /* }}} */
  237. /* Fill ib_link and trans with the correct database link and transaction. */
  238. void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */
  239. zval **link_id, ibase_db_link **ib_link, ibase_trans **trans)
  240. {
  241. int type;
  242. IBDEBUG("Transaction or database link?");
  243. if (zend_list_find(Z_LVAL_PP(link_id), &type)) {
  244. if (type == le_trans) {
  245. /* Transaction resource: make sure it refers to one link only, then
  246. fetch it; database link is stored in ib_trans->db_link[]. */
  247. IBDEBUG("Type is le_trans");
  248. ZEND_FETCH_RESOURCE(*trans, ibase_trans *, link_id, -1, LE_TRANS, le_trans);
  249. if ((*trans)->link_cnt > 1) {
  250. _php_ibase_module_error("Link id is ambiguous: transaction spans multiple connections."
  251. TSRMLS_CC);
  252. return;
  253. }
  254. *ib_link = (*trans)->db_link[0];
  255. return;
  256. }
  257. }
  258. IBDEBUG("Type is le_[p]link or id not found");
  259. /* Database link resource, use default transaction. */
  260. *trans = NULL;
  261. ZEND_FETCH_RESOURCE2(*ib_link, ibase_db_link *, link_id, -1, LE_LINK, le_link, le_plink);
  262. }
  263. /* }}} */
  264. /* destructors ---------------------- */
  265. static void _php_ibase_commit_link(ibase_db_link *link TSRMLS_DC) /* {{{ */
  266. {
  267. unsigned short i = 0, j;
  268. ibase_tr_list *l;
  269. ibase_event *e;
  270. IBDEBUG("Checking transactions to close...");
  271. for (l = link->tr_list; l != NULL; ++i) {
  272. ibase_tr_list *p = l;
  273. if (p->trans != NULL) {
  274. if (i == 0) {
  275. if (p->trans->handle != NULL) {
  276. IBDEBUG("Committing default transaction...");
  277. if (isc_commit_transaction(IB_STATUS, &p->trans->handle)) {
  278. _php_ibase_error(TSRMLS_C);
  279. }
  280. }
  281. efree(p->trans); /* default transaction is not a registered resource: clean up */
  282. } else {
  283. if (p->trans->handle != NULL) {
  284. /* non-default trans might have been rolled back by other call of this dtor */
  285. IBDEBUG("Rolling back other transactions...");
  286. if (isc_rollback_transaction(IB_STATUS, &p->trans->handle)) {
  287. _php_ibase_error(TSRMLS_C);
  288. }
  289. }
  290. /* set this link pointer to NULL in the transaction */
  291. for (j = 0; j < p->trans->link_cnt; ++j) {
  292. if (p->trans->db_link[j] == link) {
  293. p->trans->db_link[j] = NULL;
  294. break;
  295. }
  296. }
  297. }
  298. }
  299. l = l->next;
  300. efree(p);
  301. }
  302. link->tr_list = NULL;
  303. for (e = link->event_head; e; e = e->event_next) {
  304. _php_ibase_free_event(e TSRMLS_CC);
  305. e->link = NULL;
  306. }
  307. }
  308. /* }}} */
  309. static void php_ibase_commit_link_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  310. {
  311. ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
  312. _php_ibase_commit_link(link TSRMLS_CC);
  313. }
  314. /* }}} */
  315. static void _php_ibase_close_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  316. {
  317. ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
  318. _php_ibase_commit_link(link TSRMLS_CC);
  319. if (link->handle != NULL) {
  320. IBDEBUG("Closing normal link...");
  321. isc_detach_database(IB_STATUS, &link->handle);
  322. }
  323. IBG(num_links)--;
  324. efree(link);
  325. }
  326. /* }}} */
  327. static void _php_ibase_close_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  328. {
  329. ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
  330. _php_ibase_commit_link(link TSRMLS_CC);
  331. IBDEBUG("Closing permanent link...");
  332. if (link->handle != NULL) {
  333. isc_detach_database(IB_STATUS, &link->handle);
  334. }
  335. IBG(num_persistent)--;
  336. IBG(num_links)--;
  337. free(link);
  338. }
  339. /* }}} */
  340. static void _php_ibase_free_trans(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  341. {
  342. ibase_trans *trans = (ibase_trans *)rsrc->ptr;
  343. unsigned short i;
  344. IBDEBUG("Cleaning up transaction resource...");
  345. if (trans->handle != NULL) {
  346. IBDEBUG("Rolling back unhandled transaction...");
  347. if (isc_rollback_transaction(IB_STATUS, &trans->handle)) {
  348. _php_ibase_error(TSRMLS_C);
  349. }
  350. }
  351. /* now remove this transaction from all the connection-transaction lists */
  352. for (i = 0; i < trans->link_cnt; ++i) {
  353. if (trans->db_link[i] != NULL) {
  354. ibase_tr_list **l;
  355. for (l = &trans->db_link[i]->tr_list; *l != NULL; l = &(*l)->next) {
  356. if ( (*l)->trans == trans) {
  357. ibase_tr_list *p = *l;
  358. *l = p->next;
  359. efree(p);
  360. break;
  361. }
  362. }
  363. }
  364. }
  365. efree(trans);
  366. }
  367. /* }}} */
  368. /* TODO this function should be part of either Zend or PHP API */
  369. static PHP_INI_DISP(php_ibase_password_displayer_cb)
  370. {
  371. TSRMLS_FETCH();
  372. if ((type == PHP_INI_DISPLAY_ORIG && ini_entry->orig_value)
  373. || (type == PHP_INI_DISPLAY_ACTIVE && ini_entry->value)) {
  374. PUTS("********");
  375. } else if (!sapi_module.phpinfo_as_text) {
  376. PUTS("<i>no value</i>");
  377. } else {
  378. PUTS("no value");
  379. }
  380. }
  381. /* {{{ startup, shutdown and info functions */
  382. PHP_INI_BEGIN()
  383. PHP_INI_ENTRY_EX("ibase.allow_persistent", "1", PHP_INI_SYSTEM, NULL, zend_ini_boolean_displayer_cb)
  384. PHP_INI_ENTRY_EX("ibase.max_persistent", "-1", PHP_INI_SYSTEM, NULL, display_link_numbers)
  385. PHP_INI_ENTRY_EX("ibase.max_links", "-1", PHP_INI_SYSTEM, NULL, display_link_numbers)
  386. PHP_INI_ENTRY("ibase.default_db", NULL, PHP_INI_SYSTEM, NULL)
  387. PHP_INI_ENTRY("ibase.default_user", NULL, PHP_INI_ALL, NULL)
  388. PHP_INI_ENTRY_EX("ibase.default_password", NULL, PHP_INI_ALL, NULL, php_ibase_password_displayer_cb)
  389. PHP_INI_ENTRY("ibase.default_charset", NULL, PHP_INI_ALL, NULL)
  390. PHP_INI_ENTRY("ibase.timestampformat", IB_DEF_DATE_FMT " " IB_DEF_TIME_FMT, PHP_INI_ALL, NULL)
  391. PHP_INI_ENTRY("ibase.dateformat", IB_DEF_DATE_FMT, PHP_INI_ALL, NULL)
  392. PHP_INI_ENTRY("ibase.timeformat", IB_DEF_TIME_FMT, PHP_INI_ALL, NULL)
  393. PHP_INI_END()
  394. static PHP_GINIT_FUNCTION(ibase)
  395. {
  396. ibase_globals->num_persistent = ibase_globals->num_links = 0;
  397. ibase_globals->sql_code = *ibase_globals->errmsg = 0;
  398. ibase_globals->default_link = -1;
  399. }
  400. PHP_MINIT_FUNCTION(ibase)
  401. {
  402. REGISTER_INI_ENTRIES();
  403. le_link = zend_register_list_destructors_ex(_php_ibase_close_link, NULL, LE_LINK, module_number);
  404. le_plink = zend_register_list_destructors_ex(php_ibase_commit_link_rsrc, _php_ibase_close_plink, LE_PLINK, module_number);
  405. le_trans = zend_register_list_destructors_ex(_php_ibase_free_trans, NULL, LE_TRANS, module_number);
  406. REGISTER_LONG_CONSTANT("IBASE_DEFAULT", PHP_IBASE_DEFAULT, CONST_PERSISTENT);
  407. REGISTER_LONG_CONSTANT("IBASE_CREATE", PHP_IBASE_CREATE, CONST_PERSISTENT);
  408. REGISTER_LONG_CONSTANT("IBASE_TEXT", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT); /* deprecated, for BC only */
  409. REGISTER_LONG_CONSTANT("IBASE_FETCH_BLOBS", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT);
  410. REGISTER_LONG_CONSTANT("IBASE_FETCH_ARRAYS", PHP_IBASE_FETCH_ARRAYS, CONST_PERSISTENT);
  411. REGISTER_LONG_CONSTANT("IBASE_UNIXTIME", PHP_IBASE_UNIXTIME, CONST_PERSISTENT);
  412. /* transactions */
  413. REGISTER_LONG_CONSTANT("IBASE_WRITE", PHP_IBASE_WRITE, CONST_PERSISTENT);
  414. REGISTER_LONG_CONSTANT("IBASE_READ", PHP_IBASE_READ, CONST_PERSISTENT);
  415. REGISTER_LONG_CONSTANT("IBASE_COMMITTED", PHP_IBASE_COMMITTED, CONST_PERSISTENT);
  416. REGISTER_LONG_CONSTANT("IBASE_CONSISTENCY", PHP_IBASE_CONSISTENCY, CONST_PERSISTENT);
  417. REGISTER_LONG_CONSTANT("IBASE_CONCURRENCY", PHP_IBASE_CONCURRENCY, CONST_PERSISTENT);
  418. REGISTER_LONG_CONSTANT("IBASE_REC_VERSION", PHP_IBASE_REC_VERSION, CONST_PERSISTENT);
  419. REGISTER_LONG_CONSTANT("IBASE_REC_NO_VERSION", PHP_IBASE_REC_NO_VERSION, CONST_PERSISTENT);
  420. REGISTER_LONG_CONSTANT("IBASE_NOWAIT", PHP_IBASE_NOWAIT, CONST_PERSISTENT);
  421. REGISTER_LONG_CONSTANT("IBASE_WAIT", PHP_IBASE_WAIT, CONST_PERSISTENT);
  422. php_ibase_query_minit(INIT_FUNC_ARGS_PASSTHRU);
  423. php_ibase_blobs_minit(INIT_FUNC_ARGS_PASSTHRU);
  424. php_ibase_events_minit(INIT_FUNC_ARGS_PASSTHRU);
  425. php_ibase_service_minit(INIT_FUNC_ARGS_PASSTHRU);
  426. return SUCCESS;
  427. }
  428. PHP_MSHUTDOWN_FUNCTION(ibase)
  429. {
  430. #ifndef PHP_WIN32
  431. /**
  432. * When the Interbase client API library libgds.so is first loaded, it registers a call to
  433. * gds__cleanup() with atexit(), in order to clean up after itself when the process exits.
  434. * This means that the library is called at process shutdown, and cannot be unloaded beforehand.
  435. * PHP tries to unload modules after every request [dl()'ed modules], and right before the
  436. * process shuts down [modules loaded from php.ini]. This results in a segfault for this module.
  437. * By NULLing the dlopen() handle in the module entry, Zend omits the call to dlclose(),
  438. * ensuring that the module will remain present until the process exits. However, the functions
  439. * and classes exported by the module will not be available until the module is 'reloaded'.
  440. * When reloaded, dlopen() will return the handle of the already loaded module. The module will
  441. * be unloaded automatically when the process exits.
  442. */
  443. zend_module_entry *ibase_entry;
  444. if (SUCCESS == zend_hash_find(&module_registry, ibase_module_entry.name,
  445. strlen(ibase_module_entry.name) +1, (void*) &ibase_entry)) {
  446. ibase_entry->handle = NULL;
  447. }
  448. #endif
  449. UNREGISTER_INI_ENTRIES();
  450. return SUCCESS;
  451. }
  452. PHP_RSHUTDOWN_FUNCTION(ibase)
  453. {
  454. IBG(num_links) = IBG(num_persistent);
  455. IBG(default_link)= -1;
  456. RESET_ERRMSG;
  457. return SUCCESS;
  458. }
  459. PHP_MINFO_FUNCTION(ibase)
  460. {
  461. char tmp[64], *s;
  462. php_info_print_table_start();
  463. php_info_print_table_row(2, "Firebird/InterBase Support",
  464. #ifdef COMPILE_DL_INTERBASE
  465. "dynamic");
  466. #else
  467. "static");
  468. #endif
  469. #ifdef FB_API_VER
  470. snprintf( (s = tmp), sizeof(tmp), "Firebird API version %d", FB_API_VER);
  471. #elif (SQLDA_CURRENT_VERSION > 1)
  472. s = "Interbase 7.0 and up";
  473. #elif !defined(DSC_null)
  474. s = "Interbase 6";
  475. #else
  476. s = "Firebird 1.0";
  477. #endif
  478. php_info_print_table_row(2, "Compile-time Client Library Version", s);
  479. #if defined(__GNUC__) || defined(PHP_WIN32)
  480. do {
  481. info_func_t info_func = NULL;
  482. #ifdef __GNUC__
  483. info_func = (info_func_t)dlsym(RTLD_DEFAULT, "isc_get_client_version");
  484. #else
  485. HMODULE l = GetModuleHandle("fbclient");
  486. if (!l && !(l = GetModuleHandle("gds32"))) {
  487. break;
  488. }
  489. info_func = (info_func_t)GetProcAddress(l, "isc_get_client_version");
  490. #endif
  491. if (info_func) {
  492. info_func(s = tmp);
  493. } else {
  494. s = "Firebird 1.0/Interbase 6";
  495. }
  496. php_info_print_table_row(2, "Run-time Client Library Version", s);
  497. } while (0);
  498. #endif
  499. php_info_print_table_end();
  500. DISPLAY_INI_ENTRIES();
  501. }
  502. /* }}} */
  503. enum connect_args { DB = 0, USER = 1, PASS = 2, CSET = 3, ROLE = 4, BUF = 0, DLECT = 1, SYNC = 2 };
  504. static char const dpb_args[] = {
  505. 0, isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name, 0
  506. };
  507. int _php_ibase_attach_db(char **args, int *len, long *largs, isc_db_handle *db TSRMLS_DC)
  508. {
  509. short i, dpb_len, buf_len = 256;
  510. char dpb_buffer[256] = { isc_dpb_version1 }, *dpb;
  511. dpb = dpb_buffer + 1;
  512. for (i = 0; i < sizeof(dpb_args); ++i) {
  513. if (dpb_args[i] && args[i] && len[i] && buf_len > 0) {
  514. dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_args[i],(unsigned char)len[i],args[i]);
  515. dpb += dpb_len;
  516. buf_len -= dpb_len;
  517. }
  518. }
  519. if (largs[BUF] && buf_len > 0) {
  520. dpb_len = slprintf(dpb, buf_len, "%c\2%c%c", isc_dpb_num_buffers,
  521. (char)(largs[BUF] >> 8), (char)(largs[BUF] & 0xff));
  522. dpb += dpb_len;
  523. buf_len -= dpb_len;
  524. }
  525. if (largs[SYNC] && buf_len > 0) {
  526. dpb_len = slprintf(dpb, buf_len, "%c\1%c", isc_dpb_force_write, largs[SYNC] == isc_spb_prp_wm_sync ? 1 : 0);
  527. dpb += dpb_len;
  528. buf_len -= dpb_len;
  529. }
  530. if (isc_attach_database(IB_STATUS, (short)len[DB], args[DB], db, (short)(dpb-dpb_buffer), dpb_buffer)) {
  531. _php_ibase_error(TSRMLS_C);
  532. return FAILURE;
  533. }
  534. return SUCCESS;
  535. }
  536. /* }}} */
  537. static void _php_ibase_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ */
  538. {
  539. char *c, hash[16], *args[] = { NULL, NULL, NULL, NULL, NULL };
  540. int i, len[] = { 0, 0, 0, 0, 0 };
  541. long largs[] = { 0, 0, 0 };
  542. PHP_MD5_CTX hash_context;
  543. zend_rsrc_list_entry new_index_ptr, *le;
  544. isc_db_handle db_handle = NULL;
  545. ibase_db_link *ib_link;
  546. RESET_ERRMSG;
  547. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ssssllsl",
  548. &args[DB], &len[DB], &args[USER], &len[USER], &args[PASS], &len[PASS],
  549. &args[CSET], &len[CSET], &largs[BUF], &largs[DLECT], &args[ROLE], &len[ROLE],
  550. &largs[SYNC])) {
  551. RETURN_FALSE;
  552. }
  553. /* restrict to the server/db in the .ini if in safe mode */
  554. if ((!len[DB] || PG(sql_safe_mode)) && (c = INI_STR("ibase.default_db"))) {
  555. args[DB] = c;
  556. len[DB] = strlen(c);
  557. }
  558. if (!len[USER] && (c = INI_STR("ibase.default_user"))) {
  559. args[USER] = c;
  560. len[USER] = strlen(c);
  561. }
  562. if (!len[PASS] && (c = INI_STR("ibase.default_password"))) {
  563. args[PASS] = c;
  564. len[PASS] = strlen(c);
  565. }
  566. if (!len[CSET] && (c = INI_STR("ibase.default_charset"))) {
  567. args[CSET] = c;
  568. len[CSET] = strlen(c);
  569. }
  570. /* don't want usernames and passwords floating around */
  571. PHP_MD5Init(&hash_context);
  572. for (i = 0; i < sizeof(args)/sizeof(char*); ++i) {
  573. PHP_MD5Update(&hash_context,args[i],len[i]);
  574. }
  575. for (i = 0; i < sizeof(largs)/sizeof(long); ++i) {
  576. PHP_MD5Update(&hash_context,(char*)&largs[i],sizeof(long));
  577. }
  578. PHP_MD5Final(hash, &hash_context);
  579. /* try to reuse a connection */
  580. if (SUCCESS == zend_hash_find(&EG(regular_list), hash, sizeof(hash), (void *) &le)) {
  581. long xlink;
  582. int type;
  583. if (Z_TYPE_P(le) != le_index_ptr) {
  584. RETURN_FALSE;
  585. }
  586. xlink = (long) le->ptr;
  587. if (zend_list_find(xlink, &type) && ((!persistent && type == le_link) || type == le_plink)) {
  588. zend_list_addref(xlink);
  589. RETURN_RESOURCE(IBG(default_link) = xlink);
  590. } else {
  591. zend_hash_del(&EG(regular_list), hash, sizeof(hash));
  592. }
  593. }
  594. /* ... or a persistent one */
  595. switch (zend_hash_find(&EG(persistent_list), hash, sizeof(hash), (void *) &le)) {
  596. long l;
  597. static char info[] = { isc_info_base_level, isc_info_end };
  598. char result[8];
  599. ISC_STATUS status[20];
  600. case SUCCESS:
  601. if (Z_TYPE_P(le) != le_plink) {
  602. RETURN_FALSE;
  603. }
  604. /* check if connection has timed out */
  605. ib_link = (ibase_db_link *) le->ptr;
  606. if (!isc_database_info(status, &ib_link->handle, sizeof(info), info, sizeof(result), result)) {
  607. ZEND_REGISTER_RESOURCE(return_value, ib_link, le_plink);
  608. break;
  609. }
  610. zend_hash_del(&EG(persistent_list), hash, sizeof(hash));
  611. default:
  612. /* no link found, so we have to open one */
  613. if ((l = INI_INT("ibase.max_links")) != -1 && IBG(num_links) >= l) {
  614. _php_ibase_module_error("Too many open links (%ld)" TSRMLS_CC, IBG(num_links));
  615. RETURN_FALSE;
  616. }
  617. /* create the ib_link */
  618. if (FAILURE == _php_ibase_attach_db(args, len, largs, &db_handle TSRMLS_CC)) {
  619. RETURN_FALSE;
  620. }
  621. /* use non-persistent if allowed number of persistent links is exceeded */
  622. if (!persistent || ((l = INI_INT("ibase.max_persistent") != -1) && IBG(num_persistent) >= l)) {
  623. ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link));
  624. ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link);
  625. } else {
  626. zend_rsrc_list_entry new_le;
  627. ib_link = (ibase_db_link *) malloc(sizeof(ibase_db_link));
  628. /* hash it up */
  629. Z_TYPE(new_le) = le_plink;
  630. new_le.ptr = ib_link;
  631. if (FAILURE == zend_hash_update(&EG(persistent_list), hash, sizeof(hash),
  632. (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)) {
  633. free(ib_link);
  634. RETURN_FALSE;
  635. }
  636. ZEND_REGISTER_RESOURCE(return_value, ib_link, le_plink);
  637. ++IBG(num_persistent);
  638. }
  639. ib_link->handle = db_handle;
  640. ib_link->dialect = largs[DLECT] ? (unsigned short)largs[DLECT] : SQL_DIALECT_CURRENT;
  641. ib_link->tr_list = NULL;
  642. ib_link->event_head = NULL;
  643. ++IBG(num_links);
  644. }
  645. /* add it to the hash */
  646. new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
  647. Z_TYPE(new_index_ptr) = le_index_ptr;
  648. if (FAILURE == zend_hash_update(&EG(regular_list), hash, sizeof(hash),
  649. (void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)) {
  650. RETURN_FALSE;
  651. }
  652. zend_list_addref(IBG(default_link) = Z_LVAL_P(return_value));
  653. }
  654. /* }}} */
  655. /* {{{ proto resource ibase_connect(string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]])
  656. Open a connection to an InterBase database */
  657. PHP_FUNCTION(ibase_connect)
  658. {
  659. _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  660. }
  661. /* }}} */
  662. /* {{{ proto resource ibase_pconnect(string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]])
  663. Open a persistent connection to an InterBase database */
  664. PHP_FUNCTION(ibase_pconnect)
  665. {
  666. _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INI_INT("ibase.allow_persistent"));
  667. }
  668. /* }}} */
  669. /* {{{ proto bool ibase_close([resource link_identifier])
  670. Close an InterBase connection */
  671. PHP_FUNCTION(ibase_close)
  672. {
  673. zval **link_arg = NULL;
  674. ibase_db_link *ib_link;
  675. int link_id;
  676. RESET_ERRMSG;
  677. switch (ZEND_NUM_ARGS()) {
  678. case 0:
  679. link_id = IBG(default_link);
  680. IBG(default_link) = -1;
  681. break;
  682. case 1:
  683. if (zend_get_parameters_ex(1, &link_arg) == FAILURE) {
  684. RETURN_FALSE;
  685. }
  686. convert_to_long_ex(link_arg);
  687. link_id = Z_LVAL_PP(link_arg);
  688. break;
  689. default:
  690. WRONG_PARAM_COUNT;
  691. break;
  692. }
  693. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, link_arg, link_id, LE_LINK, le_link, le_plink);
  694. zend_list_delete(link_id);
  695. RETURN_TRUE;
  696. }
  697. /* }}} */
  698. /* {{{ proto bool ibase_drop_db([resource link_identifier])
  699. Drop an InterBase database */
  700. PHP_FUNCTION(ibase_drop_db)
  701. {
  702. zval **link_arg = NULL;
  703. ibase_db_link *ib_link;
  704. ibase_tr_list *l;
  705. int link_id;
  706. RESET_ERRMSG;
  707. switch (ZEND_NUM_ARGS()) {
  708. case 0:
  709. link_id = IBG(default_link);
  710. IBG(default_link) = -1;
  711. break;
  712. case 1:
  713. if (zend_get_parameters_ex(1, &link_arg) == FAILURE) {
  714. RETURN_FALSE;
  715. }
  716. convert_to_long_ex(link_arg);
  717. link_id = Z_LVAL_PP(link_arg);
  718. break;
  719. default:
  720. WRONG_PARAM_COUNT;
  721. break;
  722. }
  723. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, link_arg, link_id, LE_LINK, le_link, le_plink);
  724. if (isc_drop_database(IB_STATUS, &ib_link->handle)) {
  725. _php_ibase_error(TSRMLS_C);
  726. RETURN_FALSE;
  727. }
  728. /* isc_drop_database() doesn't invalidate the transaction handles */
  729. for (l = ib_link->tr_list; l != NULL; l = l->next) {
  730. if (l->trans != NULL) l->trans->handle = NULL;
  731. }
  732. zend_list_delete(link_id);
  733. RETURN_TRUE;
  734. }
  735. /* }}} */
  736. /* {{{ proto resource ibase_trans([int trans_args [, resource link_identifier [, ... ], int trans_args [, resource link_identifier [, ... ]] [, ...]]])
  737. Start a transaction over one or several databases */
  738. #define TPB_MAX_SIZE (8*sizeof(char))
  739. PHP_FUNCTION(ibase_trans)
  740. {
  741. unsigned short i, argn, link_cnt = 0, tpb_len = 0;
  742. char last_tpb[TPB_MAX_SIZE];
  743. ibase_db_link **ib_link = NULL;
  744. ibase_trans *ib_trans;
  745. isc_tr_handle tr_handle = NULL;
  746. ISC_STATUS result;
  747. RESET_ERRMSG;
  748. argn = ZEND_NUM_ARGS();
  749. /* (1+argn) is an upper bound for the number of links this trans connects to */
  750. ib_link = (ibase_db_link **) safe_emalloc(sizeof(ibase_db_link *),1+argn,0);
  751. if (argn > 0) {
  752. long trans_argl = 0;
  753. char *tpb;
  754. ISC_TEB *teb;
  755. zval ***args = (zval ***) safe_emalloc(sizeof(zval **),argn,0);
  756. if (zend_get_parameters_array_ex(argn, args) == FAILURE) {
  757. efree(args);
  758. efree(ib_link);
  759. RETURN_FALSE;
  760. }
  761. teb = (ISC_TEB *) safe_emalloc(sizeof(ISC_TEB),argn,0);
  762. tpb = (char *) safe_emalloc(TPB_MAX_SIZE,argn,0);
  763. /* enumerate all the arguments: assume every non-resource argument
  764. specifies modifiers for the link ids that follow it */
  765. for (i = 0; i < argn; ++i) {
  766. if (Z_TYPE_PP(args[i]) == IS_RESOURCE) {
  767. ZEND_FETCH_RESOURCE2(ib_link[link_cnt], ibase_db_link *, args[i], -1,
  768. LE_LINK, le_link, le_plink);
  769. /* copy the most recent modifier string into tbp[] */
  770. memcpy(&tpb[TPB_MAX_SIZE * link_cnt], last_tpb, TPB_MAX_SIZE);
  771. /* add a database handle to the TEB with the most recently specified set of modifiers */
  772. teb[link_cnt].db_ptr = &ib_link[link_cnt]->handle;
  773. teb[link_cnt].tpb_len = tpb_len;
  774. teb[link_cnt].tpb_ptr = &tpb[TPB_MAX_SIZE * link_cnt];
  775. ++link_cnt;
  776. } else {
  777. tpb_len = 0;
  778. convert_to_long_ex(args[i]);
  779. trans_argl = Z_LVAL_PP(args[i]);
  780. if (trans_argl != PHP_IBASE_DEFAULT) {
  781. last_tpb[tpb_len++] = isc_tpb_version3;
  782. /* access mode */
  783. if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) {
  784. last_tpb[tpb_len++] = isc_tpb_read;
  785. } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) {
  786. last_tpb[tpb_len++] = isc_tpb_write;
  787. }
  788. /* isolation level */
  789. if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) {
  790. last_tpb[tpb_len++] = isc_tpb_read_committed;
  791. if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) {
  792. last_tpb[tpb_len++] = isc_tpb_rec_version;
  793. } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) {
  794. last_tpb[tpb_len++] = isc_tpb_no_rec_version;
  795. }
  796. } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) {
  797. last_tpb[tpb_len++] = isc_tpb_consistency;
  798. } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) {
  799. last_tpb[tpb_len++] = isc_tpb_concurrency;
  800. }
  801. /* lock resolution */
  802. if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) {
  803. last_tpb[tpb_len++] = isc_tpb_nowait;
  804. } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) {
  805. last_tpb[tpb_len++] = isc_tpb_wait;
  806. }
  807. }
  808. }
  809. }
  810. if (link_cnt > 0) {
  811. result = isc_start_multiple(IB_STATUS, &tr_handle, link_cnt, teb);
  812. }
  813. efree(args);
  814. efree(tpb);
  815. efree(teb);
  816. }
  817. if (link_cnt == 0) {
  818. link_cnt = 1;
  819. ZEND_FETCH_RESOURCE2(ib_link[0], ibase_db_link *, NULL, IBG(default_link), LE_LINK,
  820. le_link, le_plink);
  821. result = isc_start_transaction(IB_STATUS, &tr_handle, 1, &ib_link[0]->handle, tpb_len, last_tpb);
  822. }
  823. /* start the transaction */
  824. if (result) {
  825. _php_ibase_error(TSRMLS_C);
  826. efree(ib_link);
  827. RETURN_FALSE;
  828. }
  829. /* register the transaction in our own data structures */
  830. ib_trans = (ibase_trans *) safe_emalloc(link_cnt-1, sizeof(ibase_db_link *), sizeof(ibase_trans));
  831. ib_trans->handle = tr_handle;
  832. ib_trans->link_cnt = link_cnt;
  833. ib_trans->affected_rows = 0;
  834. for (i = 0; i < link_cnt; ++i) {
  835. ibase_tr_list **l;
  836. ib_trans->db_link[i] = ib_link[i];
  837. /* the first item in the connection-transaction list is reserved for the default transaction */
  838. if (ib_link[i]->tr_list == NULL) {
  839. ib_link[i]->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
  840. ib_link[i]->tr_list->trans = NULL;
  841. ib_link[i]->tr_list->next = NULL;
  842. }
  843. /* link the transaction into the connection-transaction list */
  844. for (l = &ib_link[i]->tr_list; *l != NULL; l = &(*l)->next);
  845. *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
  846. (*l)->trans = ib_trans;
  847. (*l)->next = NULL;
  848. }
  849. efree(ib_link);
  850. ZEND_REGISTER_RESOURCE(return_value, ib_trans, le_trans);
  851. }
  852. /* }}} */
  853. int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans TSRMLS_DC) /* {{{ */
  854. {
  855. if (ib_link == NULL) {
  856. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid database link");
  857. return FAILURE;
  858. }
  859. /* the first item in the connection-transaction list is reserved for the default transaction */
  860. if (ib_link->tr_list == NULL) {
  861. ib_link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
  862. ib_link->tr_list->trans = NULL;
  863. ib_link->tr_list->next = NULL;
  864. }
  865. if (*trans == NULL) {
  866. ibase_trans *tr = ib_link->tr_list->trans;
  867. if (tr == NULL) {
  868. tr = (ibase_trans *) emalloc(sizeof(ibase_trans));
  869. tr->handle = NULL;
  870. tr->link_cnt = 1;
  871. tr->affected_rows = 0;
  872. tr->db_link[0] = ib_link;
  873. ib_link->tr_list->trans = tr;
  874. }
  875. if (tr->handle == NULL) {
  876. if (isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL)) {
  877. _php_ibase_error(TSRMLS_C);
  878. return FAILURE;
  879. }
  880. }
  881. *trans = tr;
  882. }
  883. return SUCCESS;
  884. }
  885. /* }}} */
  886. static void _php_ibase_trans_end(INTERNAL_FUNCTION_PARAMETERS, int commit) /* {{{ */
  887. {
  888. ibase_trans *trans = NULL;
  889. int res_id = 0;
  890. ISC_STATUS result;
  891. RESET_ERRMSG;
  892. switch (ZEND_NUM_ARGS()) {
  893. ibase_db_link *ib_link;
  894. zval **arg;
  895. int type;
  896. case 0:
  897. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK,
  898. le_link, le_plink);
  899. if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
  900. /* this link doesn't have a default transaction */
  901. _php_ibase_module_error("Default link has no default transaction" TSRMLS_CC);
  902. RETURN_FALSE;
  903. }
  904. trans = ib_link->tr_list->trans;
  905. break;
  906. case 1:
  907. if (zend_get_parameters_ex(1, &arg) == FAILURE) {
  908. RETURN_FALSE;
  909. }
  910. /* one id was passed, could be db or trans id */
  911. if (zend_list_find(Z_LVAL_PP(arg), &type) && type == le_trans) {
  912. ZEND_FETCH_RESOURCE(trans, ibase_trans *, arg, -1, LE_TRANS, le_trans);
  913. convert_to_long_ex(arg);
  914. res_id = Z_LVAL_PP(arg);
  915. } else {
  916. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, arg, -1, LE_LINK, le_link, le_plink);
  917. if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
  918. /* this link doesn't have a default transaction */
  919. _php_ibase_module_error("Link has no default transaction" TSRMLS_CC);
  920. RETURN_FALSE;
  921. }
  922. trans = ib_link->tr_list->trans;
  923. }
  924. break;
  925. default:
  926. WRONG_PARAM_COUNT;
  927. break;
  928. }
  929. switch (commit) {
  930. default: /* == case ROLLBACK: */
  931. result = isc_rollback_transaction(IB_STATUS, &trans->handle);
  932. break;
  933. case COMMIT:
  934. result = isc_commit_transaction(IB_STATUS, &trans->handle);
  935. break;
  936. case (ROLLBACK | RETAIN):
  937. result = isc_rollback_retaining(IB_STATUS, &trans->handle);
  938. break;
  939. case (COMMIT | RETAIN):
  940. result = isc_commit_retaining(IB_STATUS, &trans->handle);
  941. break;
  942. }
  943. if (result) {
  944. _php_ibase_error(TSRMLS_C);
  945. RETURN_FALSE;
  946. }
  947. /* Don't try to destroy implicitly opened transaction from list... */
  948. if ( (commit & RETAIN) == 0 && res_id != 0) {
  949. zend_list_delete(res_id);
  950. }
  951. RETURN_TRUE;
  952. }
  953. /* }}} */
  954. /* {{{ proto bool ibase_commit( resource link_identifier )
  955. Commit transaction */
  956. PHP_FUNCTION(ibase_commit)
  957. {
  958. _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT);
  959. }
  960. /* }}} */
  961. /* {{{ proto bool ibase_rollback( resource link_identifier )
  962. Rollback transaction */
  963. PHP_FUNCTION(ibase_rollback)
  964. {
  965. _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK);
  966. }
  967. /* }}} */
  968. /* {{{ proto bool ibase_commit_ret( resource link_identifier )
  969. Commit transaction and retain the transaction context */
  970. PHP_FUNCTION(ibase_commit_ret)
  971. {
  972. _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT | RETAIN);
  973. }
  974. /* }}} */
  975. /* {{{ proto bool ibase_rollback_ret( resource link_identifier )
  976. Rollback transaction and retain the transaction context */
  977. PHP_FUNCTION(ibase_rollback_ret)
  978. {
  979. _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK | RETAIN);
  980. }
  981. /* }}} */
  982. /* {{{ proto int ibase_gen_id(string generator [, int increment [, resource link_identifier ]])
  983. Increments the named generator and returns its new value */
  984. PHP_FUNCTION(ibase_gen_id)
  985. {
  986. zval *link = NULL;
  987. char query[128], *generator;
  988. int gen_len;
  989. long inc = 1;
  990. ibase_db_link *ib_link;
  991. ibase_trans *trans = NULL;
  992. XSQLDA out_sqlda;
  993. ISC_INT64 result;
  994. RESET_ERRMSG;
  995. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lr", &generator, &gen_len,
  996. &inc, &link)) {
  997. RETURN_FALSE;
  998. }
  999. PHP_IBASE_LINK_TRANS(link, ib_link, trans);
  1000. snprintf(query, sizeof(query), "SELECT GEN_ID(%s,%ld) FROM rdb$database", generator, inc);
  1001. /* allocate a minimal descriptor area */
  1002. out_sqlda.sqln = out_sqlda.sqld = 1;
  1003. out_sqlda.version = SQLDA_CURRENT_VERSION;
  1004. /* allocate the field for the result */
  1005. out_sqlda.sqlvar[0].sqltype = SQL_INT64;
  1006. out_sqlda.sqlvar[0].sqlscale = 0;
  1007. out_sqlda.sqlvar[0].sqllen = sizeof(result);
  1008. out_sqlda.sqlvar[0].sqldata = (void*) &result;
  1009. /* execute the query */
  1010. if (isc_dsql_exec_immed2(IB_STATUS, &ib_link->handle, &trans->handle, 0, query,
  1011. SQL_DIALECT_CURRENT, NULL, &out_sqlda)) {
  1012. _php_ibase_error(TSRMLS_C);
  1013. RETURN_FALSE;
  1014. }
  1015. /* don't return the generator value as a string unless it doesn't fit in a long */
  1016. #if SIZEOF_LONG < 8
  1017. if (result < LONG_MIN || result > LONG_MAX) {
  1018. char *res;
  1019. int l;
  1020. l = spprintf(&res, 0, "%" LL_MASK "d", result);
  1021. RETURN_STRINGL(res, l, 0);
  1022. }
  1023. #endif
  1024. RETURN_LONG((long)result);
  1025. }
  1026. /* }}} */
  1027. #endif /* HAVE_IBASE */
  1028. /*
  1029. * Local variables:
  1030. * tab-width: 4
  1031. * c-basic-offset: 4
  1032. * End:
  1033. * vim600: sw=4 ts=4 fdm=marker
  1034. * vim<600: sw=4 ts=4
  1035. */