From 15ff1d211bd4fb4ac751297eb1ecb64ab34345fd Mon Sep 17 00:00:00 2001 From: =?utf8?q?H=C3=A9not=20David?= Date: Mon, 17 Jul 2000 21:29:30 +0000 Subject: [PATCH] Added extension ii for Ingres II native support. @- Added extension ii for Ingres II native support. See README in ext/ii @ directory. (David H) --- MAINTAINERS | 4 + ext/ingres_ii/Makefile.in | 8 + ext/ingres_ii/README | 13 + ext/ingres_ii/config.m4 | 36 + ext/ingres_ii/ii.c | 1299 +++++++++++++++++++++++++++++++++++++ ext/ingres_ii/ii.h | 61 ++ ext/ingres_ii/php_ii.h | 106 +++ php.ini-dist | 8 + php.ini-optimized | 8 + php.ini-recommended | 8 + 10 files changed, 1551 insertions(+) create mode 100644 ext/ingres_ii/Makefile.in create mode 100644 ext/ingres_ii/README create mode 100644 ext/ingres_ii/config.m4 create mode 100644 ext/ingres_ii/ii.c create mode 100644 ext/ingres_ii/ii.h create mode 100644 ext/ingres_ii/php_ii.h diff --git a/MAINTAINERS b/MAINTAINERS index 8c3995d2bd..5b86ea2a0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -42,6 +42,10 @@ EXTENSION: hyperwave PRIMARY MAINTAINER: Uwe Steinmann STATUS: Maintained -------------------------------------------------------------------------------- +EXTENSION: ii +PRIMARY MAINTAINER: David Hénot +STATUS: Maintained +-------------------------------------------------------------------------------- EXTENSION: informix PRIMARY MAINTAINER: Danny Heijl STATUS: Maintained diff --git a/ext/ingres_ii/Makefile.in b/ext/ingres_ii/Makefile.in new file mode 100644 index 0000000000..33e6832dff --- /dev/null +++ b/ext/ingres_ii/Makefile.in @@ -0,0 +1,8 @@ +# $Id$ + +LTLIBRARY_NAME = libii.la +LTLIBRARY_SOURCES = ii.c +LTLIBRARY_SHARED_NAME = ii.la +LTLIBRARY_SHARED_LIBADD = $(II_SHARED_LIBADD) + +include $(top_srcdir)/build/dynlib.mk diff --git a/ext/ingres_ii/README b/ext/ingres_ii/README new file mode 100644 index 0000000000..21b2b12c3b --- /dev/null +++ b/ext/ingres_ii/README @@ -0,0 +1,13 @@ +Ingres II extension for PHP 4.0 +=============================== + +This extension provides access to Ingres II servers from PHP 4.0. +It is still in developpement and has been only quickly tested on +linux (Mandrake 5.3 for intel), so you should avoid using it with +critical data. + +To enable the extension just add --with-ii to your ./configure +line. If the Ingres files are not found, use --with-ii=DIR instead +to specify your Ingres installation directory. + +Please report suggestions to henot@php.net. diff --git a/ext/ingres_ii/config.m4 b/ext/ingres_ii/config.m4 new file mode 100644 index 0000000000..44df66e9ae --- /dev/null +++ b/ext/ingres_ii/config.m4 @@ -0,0 +1,36 @@ +dnl $Id$ +dnl config.m4 for extension ii + +PHP_ARG_WITH(ii, for Ingres II support, +[ --with-ii[=DIR] Include Ingres II support. DIR is the Ingres + base directory (default $II_SYSTEM/II/ingres)], +no) + +if test "$PHP_II" != "no"; then + AC_DEFINE(HAVE_II, 1, [Whether you have Ingres II]) + PHP_EXTENSION(ii, $ext_shared) + + if test "$PHP_II" = "yes"; then + II_DIR=$II_SYSTEM/ingres + else + II_DIR=$PHP_II + fi + + if test -r $II_DIR/files/iiapi.h; then + II_INC_DIR=$II_DIR/files + else + AC_MSG_ERROR(Cannot find iiapi.h under $II_DIR/files) + fi + + if test -r $II_DIR/lib/libiiapi.a; then + II_LIB_DIR=$II_DIR/lib + else + AC_MSG_ERROR(Cannot find libiiapi.a under $II_DIR/lib) + fi + + AC_ADD_LIBRARY_WITH_PATH(iiapi, $II_LIB_DIR, II_SHARED_LIBADD) + AC_ADD_LIBRARY_WITH_PATH(ingres, $II_LIB_DIR, II_SHARED_LIBADD) + + AC_ADD_INCLUDE($II_INC_DIR) +fi +PHP_SUBST(II_SHARED_LIBADD) diff --git a/ext/ingres_ii/ii.c b/ext/ingres_ii/ii.c new file mode 100644 index 0000000000..229e97ccd9 --- /dev/null +++ b/ext/ingres_ii/ii.c @@ -0,0 +1,1299 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: David Hénot | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include "php.h" +#include "php_globals.h" +#include "php_ini.h" +#include "php_ii.h" +#include "ii.h" +#include "ext/standard/php_string.h" + +#if HAVE_II + +ZEND_DECLARE_MODULE_GLOBALS(ii) + +/* True globals, no need for thread safety */ +static int le_ii_link,le_ii_plink; + +#define SAFE_STRING(s) ((s)?(s):"") + +/* Every user visible function must have an entry in ii_functions[]. +*/ +function_entry ii_functions[] = { + PHP_FE(ii_connect, NULL) + PHP_FE(ii_pconnect, NULL) + PHP_FE(ii_close, NULL) + PHP_FE(ii_query, NULL) + PHP_FE(ii_num_rows, NULL) + PHP_FE(ii_num_fields, NULL) + PHP_FE(ii_field_name, NULL) + PHP_FE(ii_field_type, NULL) + PHP_FE(ii_field_nullable, NULL) + PHP_FE(ii_field_length, NULL) + PHP_FE(ii_field_precision, NULL) + PHP_FE(ii_field_scale, NULL) + PHP_FE(ii_fetch_array, NULL) + PHP_FE(ii_fetch_row, NULL) + PHP_FE(ii_fetch_object, NULL) + PHP_FE(ii_rollback, NULL) + PHP_FE(ii_commit, NULL) + {NULL, NULL, NULL} /* Must be the last line in ii_functions[] */ +}; + +zend_module_entry ii_module_entry = { + "ii", + ii_functions, + PHP_MINIT(ii), + PHP_MSHUTDOWN(ii), + PHP_RINIT(ii), + PHP_RSHUTDOWN(ii), + PHP_MINFO(ii), + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_II +ZEND_GET_MODULE(ii) +#endif + +/* php.ini entries +*/ +PHP_INI_BEGIN() + STD_PHP_INI_BOOLEAN("ii.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateInt, allow_persistent, zend_ii_globals, ii_globals) + STD_PHP_INI_ENTRY_EX("ii.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateInt, max_persistent, zend_ii_globals, ii_globals, display_link_numbers) + STD_PHP_INI_ENTRY_EX("ii.max_links", "-1", PHP_INI_SYSTEM, OnUpdateInt, max_links, zend_ii_globals, ii_globals, display_link_numbers) + STD_PHP_INI_ENTRY("ii.default_database", NULL, PHP_INI_ALL, OnUpdateString, default_database, zend_ii_globals, ii_globals) + STD_PHP_INI_ENTRY("ii.default_user", NULL, PHP_INI_ALL, OnUpdateString, default_user, zend_ii_globals, ii_globals) + STD_PHP_INI_ENTRY("ii.default_password", NULL, PHP_INI_ALL, OnUpdateString, default_password, zend_ii_globals, ii_globals) +PHP_INI_END() + +/* closes statement in given link +*/ +static int _close_statement(II_LINK *link) +{ + IIAPI_CLOSEPARM closeParm; + + closeParm.cl_genParm.gp_callback = NULL; + closeParm.cl_genParm.gp_closure = NULL; + closeParm.cl_stmtHandle = link->stmtHandle; + + IIapi_close(&closeParm); + ii_sync(&(closeParm.cl_genParm)); + + if(ii_success(&(closeParm.cl_genParm))==II_FAIL) { + return 1; + } + + link->stmtHandle = NULL; + link->fieldCount = 0; + link->descriptor = NULL; + return 0; +} + +/* rolls back transaction in given link + after closing the active transaction (if any) +*/ +static int _rollback_transaction(II_LINK *link) +{ + IIAPI_ROLLBACKPARM rollbackParm; + + if(link->stmtHandle && _close_statement(link)) { + php_error(E_WARNING,"Ingres II: Unable to close statement !!"); + return 1; + } + + rollbackParm.rb_genParm.gp_callback = NULL; + rollbackParm.rb_genParm.gp_closure = NULL; + rollbackParm.rb_tranHandle = link->tranHandle; + rollbackParm.rb_savePointHandle = NULL; + + IIapi_rollback(&rollbackParm); + ii_sync(&(rollbackParm.rb_genParm)); + + if(ii_success(&(rollbackParm.rb_genParm))==II_FAIL) { + return 1; + } + + link->tranHandle = NULL; + return 0; +} + +/* closes the given link, actually disconnecting from server + and releasing associated resources after rolling back the + active transaction (if any) +*/ +static void _close_ii_link(II_LINK *link) +{ + IIAPI_DISCONNPARM disconnParm; + IILS_FETCH(); + + if(link->tranHandle && _rollback_transaction(link)) { + php_error(E_WARNING,"Ingres II: Unable to rollback transaction !!"); + } + + disconnParm.dc_genParm.gp_callback = NULL; + disconnParm.dc_genParm.gp_closure = NULL; + disconnParm.dc_connHandle = link->connHandle; + + IIapi_disconnect(&disconnParm); + + efree(link); + + IIG(num_links)--; +} + +/* closes the given persistent link, see _close_ii_link +*/ +static void _close_ii_plink(II_LINK *link) +{ + IILS_FETCH(); + + _close_ii_link(link); + IIG(num_persistent)--; +} + +/* sets the default link +*/ +static void php_ii_set_default_link(int id) +{ + IILS_FETCH(); + + if (IIG(default_link)!=-1) { + zend_list_delete(IIG(default_link)); + } + IIG(default_link) = id; + zend_list_addref(id); +} + +/* gets the default link + if none has been set, tries to open a new one with default + parameters +*/ +static int php_ii_get_default_link(INTERNAL_FUNCTION_PARAMETERS IILS_DC) +{ + if (IIG(default_link)==-1) { /* no link opened yet, implicitly open one */ + ht = 0; + php_ii_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + } + return IIG(default_link); +} + +/* Module initialization +*/ +PHP_MINIT_FUNCTION(ii) +{ + IIAPI_INITPARM initParm = { + -1, /* timeout in ms, -1 = no timeout */ + IIAPI_VERSION_1, /* api version used */ + 0 /* status (output) */ + }; + IILS_FETCH(); + + REGISTER_INI_ENTRIES(); + + le_ii_link = register_list_destructors(_close_ii_link,NULL); + le_ii_plink = register_list_destructors(NULL,_close_ii_plink); + + IIG(num_persistent) = 0; + + /* Constants registration */ + REGISTER_LONG_CONSTANT("II_ASSOC", II_ASSOC, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("II_NUM", II_NUM, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("II_BOTH", II_BOTH, CONST_CS | CONST_PERSISTENT); + + + /* Ingres api initialization */ + IIapi_initialize(&initParm); + if (initParm.in_status==IIAPI_ST_SUCCESS) { + return SUCCESS; + } else { + return FAILURE; + } +} + +/* Module shutdown +*/ +PHP_MSHUTDOWN_FUNCTION(ii) +{ + IIAPI_TERMPARM termParm; + + UNREGISTER_INI_ENTRIES(); + + /* Ingres api termination */ + IIapi_terminate(&termParm); + if (termParm.tm_status==IIAPI_ST_SUCCESS) { + return SUCCESS; + } else { + return FAILURE; + } +} + +/* New request initialization +*/ +PHP_RINIT_FUNCTION(ii) +{ + IILS_FETCH(); + + IIG(default_link) = -1; + IIG(num_links) = IIG(num_persistent); + return SUCCESS; +} + +/* End of request +*/ +PHP_RSHUTDOWN_FUNCTION(ii) +{ + IILS_FETCH(); + + if (IIG(default_link)!=-1) { + zend_list_delete(IIG(default_link)); + IIG(default_link) = -1; + } + return SUCCESS; +} + +/* Informations reported to phpinfo() +*/ +PHP_MINFO_FUNCTION(ii) +{ + char buf[32]; + IILS_FETCH(); + + php_info_print_table_start(); + php_info_print_table_header(2, "Ingres II Support", "enabled"); + sprintf(buf, "%ld", IIG(num_persistent)); + php_info_print_table_row(2, "Active Persistent Links", buf); + sprintf(buf, "%ld", IIG(num_links)); + php_info_print_table_row(2, "Active Links", buf); + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); +} + +/* Waits for completion of the last Ingres api call + used because of the asynchronous design of this api +*/ +static int ii_sync(IIAPI_GENPARM *genParm) +{ + static IIAPI_WAITPARM waitParm = { + -1, /* no timeout, we don't want asynchronous queries */ + 0 /* wt_status (output) */ + }; + + while( genParm->gp_completed == FALSE ) { + IIapi_wait(&waitParm); + } + + if (waitParm.wt_status != IIAPI_ST_SUCCESS) { + php_error(E_WARNING,"Ingres II: Unexpected failure of IIapi_wait()"); + return 0; + } + return 1; +} + +/* Handles errors from Ingres api +*/ +static int ii_success(IIAPI_GENPARM *genParm) +{ + switch(genParm->gp_status) { + case IIAPI_ST_SUCCESS: + return II_OK; + case IIAPI_ST_NO_DATA: + return II_NO_DATA; + default: + if(genParm->gp_errorHandle == NULL) { /* no error message available */ + php_error(E_WARNING,"Ingres II: Server or API error - no error message available"); + } else { + IIAPI_GETEINFOPARM getEInfoParm; + + getEInfoParm.ge_errorHandle = genParm->gp_errorHandle; + IIapi_getErrorInfo(&getEInfoParm); + php_error(E_WARNING,"Ingres II: Server or API error : %s", getEInfoParm.ge_message); + php_error(E_WARNING,"Ingres II: SQLSTATE : %s", getEInfoParm.ge_SQLSTATE); + } + return II_FAIL; + } +} + +/* Actually handles connection creation, either persistent or not +*/ +static void php_ii_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent) +{ + zval **database, **username, **password; + char *db, *user, *pass; + int argc; + char *hashed_details; + int hashed_details_length; + IIAPI_CONNPARM connParm; + II_LINK *link; + IILS_FETCH(); + PLS_FETCH(); + + /* Setting db, user and pass according to sql_safe_mode, parameters and/or default values */ + argc = ZEND_NUM_ARGS(); + + if (PG(sql_safe_mode)) { + + if (argc>0) { + php_error(E_NOTICE,"SQL safe mode in effect - ignoring host/user/password information"); + } + + db = pass = NULL; + user=php_get_current_user(); + hashed_details_length = strlen(user) + sizeof("ii___")-1; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"ii__%s_",user); + } else { + db = IIG(default_database); + user = IIG(default_user); + pass = IIG(default_password); + + if (argc > 3 || zend_get_parameters_ex(argc, &database, &username, &password) == FAILURE){ + WRONG_PARAM_COUNT; + } + + switch(argc) { + case 3: + convert_to_string_ex(password); + pass = (*password)->value.str.val; + /* Fall-through. */ + case 2: + convert_to_string_ex(username); + user = (*username)->value.str.val; + /* Fall-through. */ + case 1: + convert_to_string_ex(database); + db = (*database)->value.str.val; + /* Fall-through. */ + case 0: + break; + } + + hashed_details_length = sizeof("ii___")-1 + strlen(SAFE_STRING(db))+strlen(SAFE_STRING(user))+strlen(SAFE_STRING(pass)); + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"ii_%s_%s_%s",SAFE_STRING(db), SAFE_STRING(user), SAFE_STRING(pass)); + } + + /* if asked for unauthorized persistency, issue a warning + and go for a non-persistent link */ + if (persistent && !IIG(allow_persistent)) { + php_error(E_WARNING,"Ingres II: Persistent links disabled !"); + persistent = 0; + } + + if (persistent) { + list_entry *le; + + /* is this link already in the persistent list ? */ + if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) { /* no, new persistent connection */ + + list_entry new_le; + + if (IIG(max_links)!=-1 && IIG(num_links)>=IIG(max_links)) { + php_error(E_WARNING,"Ingres II: Too many open links (%d)",IIG(num_links)); + efree(hashed_details); + RETURN_FALSE; + } + if (IIG(max_persistent)!=-1 && IIG(num_persistent)>=IIG(max_persistent)) { + php_error(E_WARNING,"Ingres II: Too many open persistent links (%d)",IIG(num_persistent)); + efree(hashed_details); + RETURN_FALSE; + } + + /* create the link */ + connParm.co_genParm.gp_callback = NULL; + connParm.co_genParm.gp_closure = NULL; + connParm.co_target = db; + connParm.co_username = user; + connParm.co_password = pass; + connParm.co_timeout = -1; /* -1 is no timeout */ + connParm.co_connHandle = NULL; + connParm.co_tranHandle = NULL; + + IIapi_connect(&connParm); + + if(!ii_sync(&(connParm.co_genParm)) || ii_success(&(connParm.co_genParm)) == II_FAIL) { + efree(hashed_details); + php_error(E_WARNING,"Ingres II: Unable to connect to database (%s)", db); + RETURN_FALSE; + } + + link = (II_LINK *) emalloc(sizeof(II_LINK)); + link->connHandle = connParm.co_connHandle; + link->tranHandle = NULL; + link->stmtHandle = NULL; + link->fieldCount = 0; + link->descriptor = NULL; + + /* hash it up */ + new_le.type = le_ii_plink; + new_le.ptr = link; + if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(list_entry), NULL)==FAILURE) { + php_error(E_WARNING,"Ingres II: Unable to hash (%s)", hashed_details); + efree(hashed_details); + RETURN_FALSE; + } + IIG(num_persistent)++; + IIG(num_links)++; + } else { /* already open persistent connection */ + if (le->type != le_ii_plink) { + RETURN_FALSE; + } + /* here we should ensure that the link did not die */ + /* unable to figure out the right way to do this + maybe does the api handle the reconnection transparently ? */ + link = (II_LINK *) le->ptr; + } + ZEND_REGISTER_RESOURCE(return_value, link, le_ii_plink); + } else { /* non persistent */ + list_entry *index_ptr,new_index_ptr; + + /* first we check the hash for the hashed_details key. if it exists, + * it should point us to the right offset where the actual link sits. + * if it doesn't, open a new link, add it to the resource list, + * and add a pointer to it with hashed_details as the key. + */ + if (zend_hash_find(&EG(regular_list),hashed_details,hashed_details_length+1,(void **) &index_ptr)==SUCCESS) { + int type; + void *ptr; + + if (index_ptr->type != le_index_ptr) { + RETURN_FALSE; + } + link = (II_LINK *) index_ptr->ptr; + ptr = zend_list_find((int) link,&type); /* check if the link is still there */ + if (ptr && (type==le_ii_link || type==le_ii_plink)) { + zend_list_addref((int) link); + return_value->value.lval = (int) link; + + php_ii_set_default_link((int) link); + + return_value->type = IS_RESOURCE; + efree(hashed_details); + return; + } else { + zend_hash_del(&EG(regular_list),hashed_details,hashed_details_length+1); + } + } + if (IIG(max_links)!=-1 && IIG(num_links)>=IIG(max_links)) { + php_error(E_WARNING,"Ingres II: Too many open links (%d)",IIG(num_links)); + efree(hashed_details); + RETURN_FALSE; + } + + /* create the link */ + connParm.co_genParm.gp_callback = NULL; + connParm.co_genParm.gp_closure = NULL; + connParm.co_target = db; + connParm.co_username = user; + connParm.co_password = pass; + connParm.co_timeout = -1; /* -1 is no timeout */ + connParm.co_connHandle = NULL; + connParm.co_tranHandle = NULL; + + IIapi_connect(&connParm); + + if(!ii_sync(&(connParm.co_genParm)) || ii_success(&(connParm.co_genParm)) == II_FAIL) { + efree(hashed_details); + php_error(E_WARNING,"Ingres II: Unable to connect to database (%s)", db); + RETURN_FALSE; + } + + link = (II_LINK *) emalloc(sizeof(II_LINK)); + link->connHandle = connParm.co_connHandle; + link->tranHandle = NULL; + link->stmtHandle = NULL; + link->fieldCount = 0; + link->descriptor = NULL; + + /* add it to the list */ + ZEND_REGISTER_RESOURCE(return_value, link, le_ii_link); + + /* add it to the hash */ + new_index_ptr.ptr = (void *) return_value->value.lval; + new_index_ptr.type = le_index_ptr; + if (zend_hash_update(&EG(regular_list),hashed_details,hashed_details_length+1,(void *) &new_index_ptr, sizeof(list_entry), NULL)==FAILURE) { + php_error(E_WARNING,"Ingres II: Unable to hash (%s)", hashed_details); + efree(hashed_details); + RETURN_FALSE; + } + IIG(num_links)++; + } + efree(hashed_details); + + php_ii_set_default_link(return_value->value.lval); +} + +/* {{{ proto resource ii_connect([string database [, string username [, string password]]]) + Open a connection to an Ingres II database + the syntax of database is [node_id::]dbname[/svr_class] */ +PHP_FUNCTION(ii_connect) +{ + php_ii_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto resource ii_pconnect([string database [, string username [, string password]]]) + Open a persistent connection to an Ingres II database + the syntax of database is [node_id::]dbname[/svr_class] */ +PHP_FUNCTION(ii_pconnect) +{ + php_ii_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +/* {{{ proto bool ii_close([resource link]) + Close an Ingres II database connection */ +PHP_FUNCTION(ii_close) +{ + zval **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 1 || (argc && zend_get_parameters_ex(argc, &link) == FAILURE)){ + WRONG_PARAM_COUNT; + } + + if (argc == 0) { + link_id = IIG(default_link); + } + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + zend_list_delete(link_id); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool ii_query(string query [, resource link]) + Send a SQL query to Ingres II + Unsupported query types : + - close + - commit + - connect + - disconnect + - get dbevent + - prepare to commit + - rollback + - savepoint + - set autocommit + - + (look for dedicated functions instead) */ +PHP_FUNCTION(ii_query) +{ + zval **query, **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IIAPI_QUERYPARM queryParm; + IIAPI_GETDESCRPARM getDescrParm; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &query, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc < 2) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + convert_to_string_ex(query); + + /* if there's already an active statement, close it */ + if(ii_link->stmtHandle && _close_statement(ii_link)) { + php_error(E_WARNING,"Ingres II: Unable to close statement !!"); + RETURN_FALSE; + } + + /* send the query */ + queryParm.qy_genParm.gp_callback = NULL; + queryParm.qy_genParm.gp_closure = NULL; + queryParm.qy_connHandle = ii_link->connHandle; + queryParm.qy_tranHandle = ii_link->tranHandle; + queryParm.qy_stmtHandle = NULL; + queryParm.qy_queryType = IIAPI_QT_QUERY; + queryParm.qy_parameters = FALSE; + queryParm.qy_queryText = Z_STRVAL_PP(query); + + IIapi_query(&queryParm); + ii_sync(&(queryParm.qy_genParm)); + + if(ii_success(&(queryParm.qy_genParm))==II_FAIL) { + RETURN_FALSE; + } + + /* store transaction and statement handles */ + ii_link->tranHandle = queryParm.qy_tranHandle; + ii_link->stmtHandle = queryParm.qy_stmtHandle; + + /* get description of results */ + getDescrParm.gd_genParm.gp_callback = NULL; + getDescrParm.gd_genParm.gp_closure = NULL; + getDescrParm.gd_stmtHandle = ii_link->stmtHandle; + + IIapi_getDescriptor(&getDescrParm); + ii_sync(&(getDescrParm.gd_genParm)); + + if(ii_success(&(getDescrParm.gd_genParm))==II_FAIL) { + RETURN_FALSE; + } + + /* store the results */ + ii_link->fieldCount = getDescrParm.gd_descriptorCount; + ii_link->descriptor = getDescrParm.gd_descriptor; + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int ii_num_rows([resource link]) + Return the number of rows affected/returned by the last query + Warning : don't call ii_num_rows() before ii_fetch_xx(), + or ii_fetch_xx() wouldn't find any data */ +PHP_FUNCTION(ii_num_rows) +{ + zval **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IIAPI_GETQINFOPARM getQInfoParm; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 1 || zend_get_parameters_ex(argc, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc < 1) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + /* get number of affected rows */ + getQInfoParm.gq_genParm.gp_callback = NULL; + getQInfoParm.gq_genParm.gp_closure = NULL; + getQInfoParm.gq_stmtHandle = ii_link->stmtHandle; + + IIapi_getQueryInfo(&getQInfoParm); + ii_sync(&(getQInfoParm.gq_genParm)); + + if(ii_success(&(getQInfoParm.gq_genParm))==II_FAIL) { + RETURN_FALSE; + } + + /* return the result */ + if(getQInfoParm.gq_mask & IIAPI_GQ_ROW_COUNT) { + RETURN_LONG(getQInfoParm.gq_rowCount); + } else { + RETURN_LONG(0); + } +} +/* }}} */ + +/* {{{ proto int ii_num_fields([resource link]) + Return the number of fields returned by the last query */ +PHP_FUNCTION(ii_num_fields) +{ + zval **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 1 || zend_get_parameters_ex(argc, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc < 1) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + RETURN_LONG(ii_link->fieldCount); +} +/* }}} */ + +#define II_FIELD_INFO_NAME 1 +#define II_FIELD_INFO_TYPE 2 +#define II_FIELD_INFO_NULLABLE 3 +#define II_FIELD_INFO_LENGTH 4 +#define II_FIELD_INFO_PRECISION 5 +#define II_FIELD_INFO_SCALE 6 + +/* Return information about a field in a query result +*/ +static void php_ii_field_info(INTERNAL_FUNCTION_PARAMETERS, int info_type) +{ + zval **idx, **link; + int argc; + int link_id = -1; + char *name, *fun_name; + int index; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &idx, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc < 2) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + convert_to_long_ex(idx); + index = Z_LVAL_PP(idx); + + if(index < 1 || index > ii_link->fieldCount) { + switch(info_type) { + case II_FIELD_INFO_NAME: + fun_name = "ii_field_name"; + break; + case II_FIELD_INFO_TYPE: + fun_name = "ii_field_type"; + break; + case II_FIELD_INFO_NULLABLE: + fun_name = "ii_field_nullable"; + break; + case II_FIELD_INFO_LENGTH: + fun_name = "ii_field_length"; + break; + case II_FIELD_INFO_PRECISION: + fun_name = "ii_field_precision"; + break; + case II_FIELD_INFO_SCALE: + fun_name = "ii_field_scale"; + break; + default: + break; + } + php_error(E_WARNING,"Ingres II: %s() called with wrong index (%d)",fun_name,index); + RETURN_FALSE; + } + + switch (info_type) { + case II_FIELD_INFO_NAME: + name = php_ii_field_name(ii_link, index); + if(name == NULL) { + RETURN_FALSE; + } + RETURN_STRING(name, 1); + break; + case II_FIELD_INFO_TYPE: + switch((ii_link->descriptor[index - 1]).ds_dataType) { + case IIAPI_BYTE_TYPE: RETURN_STRING("IIAPI_BYTE_TYPE",1); + case IIAPI_CHA_TYPE: RETURN_STRING("IIAPI_CHA_TYPE",1); + case IIAPI_CHR_TYPE: RETURN_STRING("IIAPI_CHR_TYPE",1); + case IIAPI_DEC_TYPE: RETURN_STRING("IIAPI_DEC_TYPE",1); + case IIAPI_DTE_TYPE: RETURN_STRING("IIAPI_DTE_TYPE",1); + case IIAPI_FLT_TYPE: RETURN_STRING("IIAPI_FLT_TYPE",1); + case IIAPI_INT_TYPE: RETURN_STRING("IIAPI_INT_TYPE",1); + case IIAPI_LOGKEY_TYPE: RETURN_STRING("IIAPI_LOGKEY_TYPE",1); + case IIAPI_LBYTE_TYPE: RETURN_STRING("IIAPI_LBYTE_TYPE",1); + case IIAPI_LVCH_TYPE: RETURN_STRING("IIAPI_LVCH_TYPE",1); + case IIAPI_MNY_TYPE: RETURN_STRING("IIAPI_MNY_TYPE",1); + case IIAPI_TABKEY_TYPE: RETURN_STRING("IIAPI_TABKEY_TYPE",1); + case IIAPI_TXT_TYPE: RETURN_STRING("IIAPI_TXT_TYPE",1); + case IIAPI_VBYTE_TYPE: RETURN_STRING("IIAPI_VBYTE_TYPE",1); + case IIAPI_VCH_TYPE: RETURN_STRING("IIAPI_VCH_TYPE",1); + default: + php_error(E_WARNING,"Ingres II: Unknown Ingres data type"); + RETURN_FALSE; + break; + } + break; + case II_FIELD_INFO_NULLABLE: + if((ii_link->descriptor[index - 1]).ds_nullable) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } + break; + case II_FIELD_INFO_LENGTH: + RETURN_LONG((ii_link->descriptor[index - 1]).ds_length); + break; + case II_FIELD_INFO_PRECISION: + RETURN_LONG((ii_link->descriptor[index - 1]).ds_precision); + break; + case II_FIELD_INFO_SCALE: + RETURN_LONG((ii_link->descriptor[index - 1]).ds_scale); + break; + default: + RETURN_FALSE; + } +} + +/* Return the name of a field in a query result +*/ +static char *php_ii_field_name(II_LINK *ii_link, int index) +{ + if(index < 1 || index > ii_link->fieldCount) { + php_error(E_WARNING,"Ingres II: php_ii_field_name() called with wrong index (%d)",index); + return NULL; + } + + return (ii_link->descriptor[index - 1]).ds_columnName; +} + +/* {{{ proto string ii_field_name(int index [, resource link]) + Return the name of a field in a query result + index must be >0 and <= ii_num_fields() */ +PHP_FUNCTION(ii_field_name) +{ + php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_NAME); +} +/* }}} */ + +/* {{{ proto string ii_field_type(int index [, resource link]) + Return the type of a field in a query result + index must be >0 and <= ii_num_fields() */ +PHP_FUNCTION(ii_field_type) +{ + php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_TYPE); +} +/* }}} */ + +/* {{{ proto string ii_field_nullable(int index [, resource link]) + Return true if the field is nullable and false otherwise + index must be >0 and <= ii_num_fields() */ +PHP_FUNCTION(ii_field_nullable) +{ + php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_NULLABLE); +} +/* }}} */ + +/* {{{ proto string ii_field_length(int index [, resource link]) + Return the length of a field in a query result + index must be >0 and <= ii_num_fields() */ +PHP_FUNCTION(ii_field_length) +{ + php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_LENGTH); +} +/* }}} */ + +/* {{{ proto string ii_field_precision(int index [, resource link]) + Return the precision of a field in a query result + index must be >0 and <= ii_num_fields() */ +PHP_FUNCTION(ii_field_precision) +{ + php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_PRECISION); +} +/* }}} */ + +/* {{{ proto string ii_field_scale(int index [, resource link]) + Return the scale of a field in a query result + index must be >0 and <= ii_num_fields() */ +PHP_FUNCTION(ii_field_scale) +{ + php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_SCALE); +} +/* }}} */ + +/* Convert complex Ingres data types to php-usable ones +*/ +#define IIAPI_CONVERT(destType,destSize,precision) {\ + convertParm.cv_srcDesc.ds_dataType = (ii_link->descriptor[i+k-2]).ds_dataType;\ + convertParm.cv_srcDesc.ds_nullable = (ii_link->descriptor[i+k-2]).ds_nullable;\ + convertParm.cv_srcDesc.ds_length = (ii_link->descriptor[i+k-2]).ds_length;\ + convertParm.cv_srcDesc.ds_precision = (ii_link->descriptor[i+k-2]).ds_precision;\ + convertParm.cv_srcDesc.ds_scale = (ii_link->descriptor[i+k-2]).ds_scale;\ + convertParm.cv_srcDesc.ds_columnType = (ii_link->descriptor[i+k-2]).ds_columnType;\ + convertParm.cv_srcDesc.ds_columnName = (ii_link->descriptor[i+k-2]).ds_columnName;\ + convertParm.cv_srcValue.dv_null = columnData[k-1].dv_null;\ + convertParm.cv_srcValue.dv_length = columnData[k-1].dv_length;\ + convertParm.cv_srcValue.dv_value = columnData[k-1].dv_value;\ + convertParm.cv_dstDesc.ds_dataType = destType;\ + convertParm.cv_dstDesc.ds_nullable = FALSE;\ + convertParm.cv_dstDesc.ds_length = destSize;\ + convertParm.cv_dstDesc.ds_precision = precision;\ + convertParm.cv_dstDesc.ds_scale = 0;\ + convertParm.cv_dstDesc.ds_columnType = IIAPI_COL_TUPLE;\ + convertParm.cv_dstDesc.ds_columnName = NULL;\ + convertParm.cv_dstValue.dv_null = FALSE;\ + convertParm.cv_dstValue.dv_length = convertParm.cv_dstDesc.ds_length;\ + convertParm.cv_dstValue.dv_value = emalloc(convertParm.cv_dstDesc.ds_length+1);\ +\ + IIapi_convertData(&convertParm);\ +\ + if(ii_success(&(getColParm.gc_genParm))!=II_OK) {\ + RETURN_FALSE;\ + }\ +\ + columnData[k-1].dv_length = convertParm.cv_dstValue.dv_length;\ + columnData[k-1].dv_value = convertParm.cv_dstValue.dv_value;\ + efree(convertParm.cv_srcValue.dv_value);} + +/* Fetch a row of result +*/ +static void php_ii_fetch(INTERNAL_FUNCTION_PARAMETERS, II_LINK *ii_link, int result_type) +{ + IIAPI_GETCOLPARM getColParm; + IIAPI_DATAVALUE *columnData; + IIAPI_CONVERTPARM convertParm; + int i,j,k; + int more; + double value_double; + long value_long; + char *value_char_p; + int len, should_copy, correct_length; + PLS_FETCH(); + + /* array initialization */ + if (array_init(return_value)==FAILURE) { + RETURN_FALSE; + } + + /* going through all fields */ + for (i=1; i<=ii_link->fieldCount;) { + j = 1; + + /* as long as there are no long byte or long varchar fields, + Ingres is able to fetch many fields at a time, so try to find + these types and stop if they're found. + variable j will get number of fields to fetch */ + if ((ii_link->descriptor[i]).ds_dataType != IIAPI_LBYTE_TYPE && + (ii_link->descriptor[i]).ds_dataType != IIAPI_LVCH_TYPE) { + while ((ii_link->descriptor[i+j-1]).ds_dataType != IIAPI_LBYTE_TYPE && + (ii_link->descriptor[i+j-1]).ds_dataType != IIAPI_LVCH_TYPE && + i+j <= ii_link->fieldCount) { + j++; + } + } + + /* allocate memory for j fields */ + columnData = (IIAPI_DATAVALUE *) emalloc(j*sizeof(IIAPI_DATAVALUE)); + for(k=1; k<=j; k++) { + columnData[k-1].dv_value = (II_PTR) emalloc((ii_link->descriptor[i+k-2]).ds_length); + } + + more = 1; /* this is for multi segment LBYTE and LVCH elements */ + while (more) { + getColParm.gc_genParm.gp_callback = NULL; + getColParm.gc_genParm.gp_closure = NULL; + getColParm.gc_rowCount = 1; + getColParm.gc_columnCount = j; + getColParm.gc_columnData = columnData; + getColParm.gc_stmtHandle = ii_link->stmtHandle; + getColParm.gc_moreSegments = 0; + + IIapi_getColumns(&getColParm); + ii_sync(&(getColParm.gc_genParm)); + + if(ii_success(&(getColParm.gc_genParm))!=II_OK) { + RETURN_FALSE; + } + + more = getColParm.gc_moreSegments; + if(more){ /* more segments of LBYTE or LVCH element to come */ + /* Multi segment LBYTE and LVCH elements not supported yet */ + php_error(E_ERROR,"Ingres II: Multi segment LBYTE and LVCH elements not supported yet"); + } else { + for(k=1; k<=j; k++) { + if(columnData[k-1].dv_null) { /* NULL value ? */ + + if(result_type & II_NUM) { + add_index_unset(return_value, i+k-1); + } + if(result_type & II_ASSOC) { + add_assoc_unset(return_value, php_ii_field_name(ii_link, i+k-1)); + } + + } else { /* non NULL value */ + correct_length = 0; + + switch((ii_link->descriptor[i+k-2]).ds_dataType) { + case IIAPI_DEC_TYPE: /* decimal (fixed point number) */ + case IIAPI_MNY_TYPE: /* money */ + /* convert to floating point number */ + IIAPI_CONVERT(IIAPI_FLT_TYPE,sizeof(II_FLOAT8),53); + /* NO break */ + case IIAPI_FLT_TYPE: /* floating point number */ + switch(columnData[k-1].dv_length) { + case 4: + value_double = (double) *((II_FLOAT4 *) columnData[k-1].dv_value); + break; + case 8: + value_double = (double) *((II_FLOAT8 *) columnData[k-1].dv_value); + break; + default: + php_error(E_WARNING,"Ingres II: Invalid size for IIAPI_FLT_TYPE data (%d)",columnData[k-1].dv_length); + break; + } + if(result_type & II_NUM) { + add_index_double(return_value, i+k-1, value_double); + } + if(result_type & II_ASSOC) { + add_assoc_double(return_value, php_ii_field_name(ii_link, i+k-1), value_double); + } + break; + case IIAPI_INT_TYPE: /* integer */ + switch(columnData[k-1].dv_length) { + case 1: + value_long = (long) *((II_INT1 *) columnData[k-1].dv_value); + break; + case 2: + value_long = (long) *((II_INT2 *) columnData[k-1].dv_value); + break; + case 4: + value_long = (long) *((II_INT4 *) columnData[k-1].dv_value); + break; + default: + php_error(E_WARNING,"Ingres II: Invalid size for IIAPI_INT_TYPE data (%d)",columnData[k-1].dv_length); + break; + } + if(result_type & II_NUM) { + add_index_long(return_value, i+k-1, value_long); + } + if(result_type & II_ASSOC) { + add_assoc_long(return_value, php_ii_field_name(ii_link, i+k-1), value_long); + } + break; + case IIAPI_TXT_TYPE: /* variable length character string */ + case IIAPI_VBYTE_TYPE: /* variable length binary string */ + case IIAPI_VCH_TYPE: /* variable length character string */ + /* real length is stored in first 2 bytes of data, so adjust + length variable and data pointer */ + columnData[k-1].dv_length = *((II_INT2 *) columnData[k-1].dv_value); + ((II_INT2 *)columnData[k-1].dv_value)++; + correct_length = 1; + /* NO break */ + case IIAPI_BYTE_TYPE: /* fixed length binary string */ + case IIAPI_CHA_TYPE: /* fixed length character string */ + case IIAPI_CHR_TYPE: /* fixed length character string */ + case IIAPI_LOGKEY_TYPE: /* value unique to database */ + case IIAPI_TABKEY_TYPE: /* value unique to table */ + case IIAPI_DTE_TYPE: /* date */ + /* eventualy convert date to string */ + if((ii_link->descriptor[i+k-2]).ds_dataType==IIAPI_DTE_TYPE) { + IIAPI_CONVERT(IIAPI_CHA_TYPE,32,0); + } + /* use php_addslashes if asked to */ + if(PG(magic_quotes_runtime)) { + value_char_p = php_addslashes((char *) columnData[k-1].dv_value,columnData[k-1].dv_length,&len,0); + should_copy = 0; + } else { + value_char_p = (char *) columnData[k-1].dv_value; + len = columnData[k-1].dv_length; + should_copy = 1; + } + + if(result_type & II_NUM) { + add_index_stringl(return_value, i+k-1, value_char_p, len, should_copy); + } + if(result_type & II_ASSOC) { + add_assoc_stringl(return_value, php_ii_field_name(ii_link, i+k-1), value_char_p, len, should_copy); + } + /* eventualy restore data pointer state for + variable length data types */ + if(correct_length) { + ((II_INT2 *)columnData[k-1].dv_value)--; + } + break; + default: + php_error(E_WARNING,"Ingres II: Invalid SQL data type in fetched field (%d -- length : %d)",(ii_link->descriptor[i+k-2]).ds_dataType,columnData[k-1].dv_length); + break; + } + } + } + } + } + /* free the memory buffers */ + for(k=1; k<=j; k++) { + efree(columnData[k-1].dv_value); + } + efree(columnData); + + /* increase field pointer by number of fetched fields */ + i+=j; + } + +} + +/* {{{ proto array ii_fetch_array([int result_type [, resource link]]) + Fetch a row of result into an array + result_type can be II_NUM for enumerated array, II_ASSOC for + associative array, or II_BOTH (default) */ +PHP_FUNCTION(ii_fetch_array) +{ + zval **result_type, **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 2 || zend_get_parameters_ex(argc, &result_type, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc != 2) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + + if (argc != 0) { + convert_to_long_ex(result_type); + } + + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + php_ii_fetch(INTERNAL_FUNCTION_PARAM_PASSTHRU, ii_link, + (argc == 0 ? II_BOTH : Z_LVAL_PP(result_type))); +} +/* }}} */ + +/* {{{ proto array ii_fetch_row([resource link]]) + Fetch a row of result into an enumerated array */ +PHP_FUNCTION(ii_fetch_row) +{ + zval **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 1 || zend_get_parameters_ex(argc, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc != 1) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + php_ii_fetch(INTERNAL_FUNCTION_PARAM_PASSTHRU, ii_link, II_NUM); +} +/* }}} */ + +/* {{{ proto array ii_fetch_object([int result_type [, resource link]]) + Fetch a row of result into an object + result_type can be II_NUM for enumerated object, II_ASSOC for + associative object, or II_BOTH (default) */ +PHP_FUNCTION(ii_fetch_object) +{ + zval **result_type, **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 2 || zend_get_parameters_ex(argc, &result_type, &link) == FAILURE){ + WRONG_PARAM_COUNT; + } + + if (argc != 2) { + link_id = php_ii_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU IILS_CC); + } + + if (argc != 0) { + convert_to_long_ex(result_type); + } + + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + php_ii_fetch(INTERNAL_FUNCTION_PARAM_PASSTHRU, ii_link, + (argc == 0 ? II_BOTH : Z_LVAL_PP(result_type))); + if(Z_TYPE_P(return_value)==IS_ARRAY) { + convert_to_object(return_value); + } +} +/* }}} */ + +/* {{{ proto bool ii_rollback([resource link]) + Roll back a transaction */ +PHP_FUNCTION(ii_rollback) +{ + zval **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 1 || (argc && zend_get_parameters_ex(argc, &link) == FAILURE)){ + WRONG_PARAM_COUNT; + } + + if (argc == 0) { + link_id = IIG(default_link); + } + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + if(_rollback_transaction(ii_link)) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool ii_commit([resource link]) + Commit a transaction */ +PHP_FUNCTION(ii_commit) +{ + zval **link; + int argc; + int link_id = -1; + II_LINK *ii_link; + IIAPI_COMMITPARM commitParm; + IILS_FETCH(); + + argc = ZEND_NUM_ARGS(); + if (argc > 1 || (argc && zend_get_parameters_ex(argc, &link) == FAILURE)){ + WRONG_PARAM_COUNT; + } + + if (argc == 0) { + link_id = IIG(default_link); + } + ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink); + + if(ii_link->stmtHandle && _close_statement(ii_link)) { + php_error(E_WARNING,"Ingres II: Unable to close statement !!"); + RETURN_FALSE; + } + + commitParm.cm_genParm.gp_callback = NULL; + commitParm.cm_genParm.gp_closure = NULL; + commitParm.cm_tranHandle = ii_link->tranHandle; + + IIapi_commit(&commitParm); + ii_sync(&(commitParm.cm_genParm)); + + if(ii_success(&(commitParm.cm_genParm))==II_FAIL) { + RETURN_FALSE; + } + + ii_link->tranHandle = NULL; + RETURN_TRUE; +} +/* }}} */ + +#endif /* HAVE_II */ + diff --git a/ext/ingres_ii/ii.h b/ext/ingres_ii/ii.h new file mode 100644 index 0000000000..96058efc72 --- /dev/null +++ b/ext/ingres_ii/ii.h @@ -0,0 +1,61 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: David Hénot | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef II_H +#define II_H + +#if HAVE_II + +#include "iiapi.h" + +typedef struct _II_LINK { + II_PTR connHandle; + II_PTR tranHandle; + II_PTR stmtHandle; + II_LONG fieldCount; + IIAPI_DESCRIPTOR *descriptor; +} II_LINK; + +static int ii_sync(IIAPI_GENPARM *genParm); +static int ii_success(IIAPI_GENPARM *genParm); +#define II_FAIL 0 +#define II_OK 1 +#define II_NO_DATA 2 +static int _close_statement(II_LINK *link); +static int _rollback_transaction(II_LINK *link); +static void _close_ii_link(II_LINK *link); +static void _close_ii_plink(II_LINK *link); +static int php_ii_get_default_link(INTERNAL_FUNCTION_PARAMETERS IILS_DC); +static void php_ii_set_default_link(int id); +static void php_ii_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent); +static char *php_ii_field_name(II_LINK *ii_link, int index); +static void php_ii_field_info(INTERNAL_FUNCTION_PARAMETERS, int info_type); +static void php_ii_fetch(INTERNAL_FUNCTION_PARAMETERS, II_LINK *ii_link, int result_type); + +#endif /* HAVE_II */ +#endif /* II_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/ext/ingres_ii/php_ii.h b/ext/ingres_ii/php_ii.h new file mode 100644 index 0000000000..18008e48d8 --- /dev/null +++ b/ext/ingres_ii/php_ii.h @@ -0,0 +1,106 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: David Hénot | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef PHP_II_H +#define PHP_II_H + +#if HAVE_II + +extern zend_module_entry ii_module_entry; +#define phpext_ii_ptr &ii_module_entry + +#ifdef PHP_WIN32 +#define PHP_II_API __declspec(dllexport) +#else +#define PHP_II_API +#endif + +PHP_MINIT_FUNCTION(ii); +PHP_MSHUTDOWN_FUNCTION(ii); +PHP_RINIT_FUNCTION(ii); +PHP_RSHUTDOWN_FUNCTION(ii); +PHP_MINFO_FUNCTION(ii); + +PHP_FUNCTION(ii_connect); +PHP_FUNCTION(ii_pconnect); +PHP_FUNCTION(ii_close); +PHP_FUNCTION(ii_query); +PHP_FUNCTION(ii_num_rows); +PHP_FUNCTION(ii_num_fields); +PHP_FUNCTION(ii_field_name); +PHP_FUNCTION(ii_field_type); +PHP_FUNCTION(ii_field_nullable); +PHP_FUNCTION(ii_field_length); +PHP_FUNCTION(ii_field_precision); +PHP_FUNCTION(ii_field_scale); +PHP_FUNCTION(ii_fetch_array); +PHP_FUNCTION(ii_fetch_row); +PHP_FUNCTION(ii_fetch_object); +PHP_FUNCTION(ii_rollback); +PHP_FUNCTION(ii_commit); + +ZEND_BEGIN_MODULE_GLOBALS(ii) + long allow_persistent; + long max_persistent; + long max_links; + char *default_database; + char *default_user; + char *default_password; + + long num_persistent; + long num_links; + long default_link; +ZEND_END_MODULE_GLOBALS(ii) + +#define II_ASSOC (1<<0) +#define II_NUM (1<<1) +#define II_BOTH (II_ASSOC|II_NUM) + +#ifdef ZTS +#define IILS_D php_ii_globals *ii_globals +#define IILS_DC , IILS_D +#define IILS_C ii_globals +#define IILS_CC , IILS_C +#define IIG(v) (ii_globals->v) +#define IILS_FETCH() php_ii_globals *ii_globals = ts_resource(ii_globals_id) +#else +#define IILS_D +#define IILS_DC +#define IILS_C +#define IILS_CC +#define IIG(v) (ii_globals.v) +#define IILS_FETCH() +#endif + +#else + +#define phpext_ii_ptr NULL + +#endif + +#endif /* PHP_II_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/php.ini-dist b/php.ini-dist index a1597694b7..fa6babc67a 100644 --- a/php.ini-dist +++ b/php.ini-dist @@ -417,6 +417,14 @@ mssql.compatability_mode = Off ; compatability mode with old versions of PHP 3.0 ;assert.callback = 0 ; user-function to be called if an assertion fails. ;assert.quiet_eval = 0 ; eval the expression with current error_reporting(). set to true if you want error_reporting(0) around the eval(). +[Ingres II] +ii.allow_persistent = On ; allow or prevent persistent link +ii.max_persistent = -1 ; maximum number of persistent links. (-1 means no limit) +ii.max_links = -1 ; maximum number of links, including persistents (-1 means no limit) +ii.default_database = ; default database (format : [node_id::]dbname[/srv_class] +ii.default_user = ; default user +ii.default_password = ; default password + ; Local Variables: ; tab-width: 4 ; End: diff --git a/php.ini-optimized b/php.ini-optimized index 2321976fff..26c87def03 100644 --- a/php.ini-optimized +++ b/php.ini-optimized @@ -404,6 +404,14 @@ mssql.compatability_mode = Off ; compatability mode with old versions of PHP 3.0 ;assert.callback = 0 ; user-function to be called if an assertion fails. ;assert.quiet_eval = 0 ; eval the expression with current error_reporting(). set to true if you want error_reporting(0) around the eval(). +[Ingres II] +ii.allow_persistent = On ; allow or prevent persistent link +ii.max_persistent = -1 ; maximum number of persistent links. (-1 means no limit) +ii.max_links = -1 ; maximum number of links, including persistents (-1 means no limit) +ii.default_database = ; default database (format : [node_id::]dbname[/srv_class] +ii.default_user = ; default user +ii.default_password = ; default password + ; Local Variables: ; tab-width: 4 ; End: diff --git a/php.ini-recommended b/php.ini-recommended index 2321976fff..26c87def03 100644 --- a/php.ini-recommended +++ b/php.ini-recommended @@ -404,6 +404,14 @@ mssql.compatability_mode = Off ; compatability mode with old versions of PHP 3.0 ;assert.callback = 0 ; user-function to be called if an assertion fails. ;assert.quiet_eval = 0 ; eval the expression with current error_reporting(). set to true if you want error_reporting(0) around the eval(). +[Ingres II] +ii.allow_persistent = On ; allow or prevent persistent link +ii.max_persistent = -1 ; maximum number of persistent links. (-1 means no limit) +ii.max_links = -1 ; maximum number of links, including persistents (-1 means no limit) +ii.default_database = ; default database (format : [node_id::]dbname[/srv_class] +ii.default_user = ; default user +ii.default_password = ; default password + ; Local Variables: ; tab-width: 4 ; End: -- 2.50.1