mirror of
https://github.com/php/php-src.git
synced 2024-12-20 07:20:33 +08:00
1545 lines
44 KiB
C
1545 lines
44 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 4 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2003 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.0 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_0.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. |
|
|
+----------------------------------------------------------------------+
|
|
| Contributed by ECL IP'S Software & Services |
|
|
| http://www.eclips-software.com |
|
|
| mailto://idev@eclips-software.com |
|
|
| Author: David Hénot <henot@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "php_globals.h"
|
|
#include "php_ini.h"
|
|
#include "ext/standard/info.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(ingres_connect, NULL)
|
|
PHP_FE(ingres_pconnect, NULL)
|
|
PHP_FE(ingres_close, NULL)
|
|
PHP_FE(ingres_query, NULL)
|
|
PHP_FE(ingres_num_rows, NULL)
|
|
PHP_FE(ingres_num_fields, NULL)
|
|
PHP_FE(ingres_field_name, NULL)
|
|
PHP_FE(ingres_field_type, NULL)
|
|
PHP_FE(ingres_field_nullable, NULL)
|
|
PHP_FE(ingres_field_length, NULL)
|
|
PHP_FE(ingres_field_precision, NULL)
|
|
PHP_FE(ingres_field_scale, NULL)
|
|
PHP_FE(ingres_fetch_array, NULL)
|
|
PHP_FE(ingres_fetch_row, NULL)
|
|
PHP_FE(ingres_fetch_object, NULL)
|
|
PHP_FE(ingres_rollback, NULL)
|
|
PHP_FE(ingres_commit, NULL)
|
|
PHP_FE(ingres_autocommit, NULL)
|
|
{NULL, NULL, NULL} /* Must be the last line in ii_functions[] */
|
|
};
|
|
|
|
zend_module_entry ingres_ii_module_entry = {
|
|
STANDARD_MODULE_HEADER,
|
|
"ingres_ii",
|
|
ii_functions,
|
|
PHP_MINIT(ii),
|
|
PHP_MSHUTDOWN(ii),
|
|
PHP_RINIT(ii),
|
|
PHP_RSHUTDOWN(ii),
|
|
PHP_MINFO(ii),
|
|
NO_VERSION_YET,
|
|
STANDARD_MODULE_PROPERTIES
|
|
};
|
|
|
|
#ifdef COMPILE_DL_INGRES_II
|
|
ZEND_GET_MODULE(ingres_ii)
|
|
#endif
|
|
|
|
/* php.ini entries
|
|
*/
|
|
PHP_INI_BEGIN()
|
|
STD_PHP_INI_BOOLEAN("ingres.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_ii_globals, ii_globals)
|
|
STD_PHP_INI_ENTRY_EX("ingres.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_ii_globals, ii_globals, display_link_numbers)
|
|
STD_PHP_INI_ENTRY_EX("ingres.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_ii_globals, ii_globals, display_link_numbers)
|
|
STD_PHP_INI_ENTRY("ingres.default_database", NULL, PHP_INI_ALL, OnUpdateString, default_database, zend_ii_globals, ii_globals)
|
|
STD_PHP_INI_ENTRY("ingres.default_user", NULL, PHP_INI_ALL, OnUpdateString, default_user, zend_ii_globals, ii_globals)
|
|
STD_PHP_INI_ENTRY("ingres.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 TSRMLS_DC)
|
|
{
|
|
IIAPI_ROLLBACKPARM rollbackParm;
|
|
|
|
if (link->stmtHandle && _close_statement(link)) {
|
|
php_error_docref(NULL TSRMLS_CC, 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;
|
|
}
|
|
|
|
static void _close_ii_link(II_LINK *link TSRMLS_DC)
|
|
{
|
|
IIAPI_DISCONNPARM disconnParm;
|
|
|
|
if (link->tranHandle && _rollback_transaction(link TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, 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);
|
|
|
|
free(link);
|
|
|
|
IIG(num_links)--;
|
|
}
|
|
|
|
/* closes the given link, actually disconnecting from server
|
|
and releasing associated resources after rolling back the
|
|
active transaction (if any)
|
|
*/
|
|
static void php_close_ii_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
|
{
|
|
II_LINK *link = (II_LINK *) rsrc->ptr;
|
|
|
|
_close_ii_link(link TSRMLS_CC);
|
|
}
|
|
|
|
/* closes the given persistent link, see _close_ii_link
|
|
*/
|
|
static void _close_ii_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
|
{
|
|
II_LINK *link = (II_LINK *) rsrc->ptr;
|
|
|
|
_close_ii_link(link TSRMLS_CC);
|
|
IIG(num_persistent)--;
|
|
}
|
|
|
|
/* cleans up the given persistent link.
|
|
used when the request ends to 'refresh' the link for use
|
|
by the next request
|
|
*/
|
|
static void _ai_clean_ii_plink(II_LINK *link TSRMLS_DC)
|
|
{
|
|
int ai_error = 0;
|
|
IIAPI_DISCONNPARM disconnParm;
|
|
IIAPI_AUTOPARM autoParm;
|
|
|
|
/* if link as always been marked as broken do nothing */
|
|
/* This because we call this function directly from close function */
|
|
/* And it's called in the end of request */
|
|
if (link->connHandle == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (link->stmtHandle && _close_statement(link)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to close statement !!");
|
|
ai_error = 1;
|
|
}
|
|
|
|
if (link->autocommit) {
|
|
autoParm.ac_genParm.gp_callback = NULL;
|
|
autoParm.ac_genParm.gp_closure = NULL;
|
|
autoParm.ac_connHandle = link->connHandle;
|
|
autoParm.ac_tranHandle = link->tranHandle;
|
|
|
|
IIapi_autocommit(&autoParm);
|
|
ii_sync(&(autoParm.ac_genParm));
|
|
|
|
if (ii_success(&(autoParm.ac_genParm)) == II_FAIL) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to disable autocommit");
|
|
}
|
|
|
|
link->autocommit = 0;
|
|
link->tranHandle = NULL;
|
|
}
|
|
|
|
if (link->tranHandle && _rollback_transaction(link TSRMLS_CC)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to rollback transaction !!");
|
|
}
|
|
|
|
/* Assume link is broken, close it, and mark it as broken with conn Handle NULL */
|
|
if (ai_error) {
|
|
disconnParm.dc_genParm.gp_callback = NULL;
|
|
disconnParm.dc_genParm.gp_closure = NULL;
|
|
disconnParm.dc_connHandle = link->connHandle;
|
|
|
|
IIapi_disconnect(&disconnParm);
|
|
link->connHandle = NULL;
|
|
}
|
|
}
|
|
|
|
static void _clean_ii_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
|
{
|
|
II_LINK *link = (II_LINK *)rsrc->ptr;
|
|
_ai_clean_ii_plink(link TSRMLS_CC);
|
|
}
|
|
|
|
/* sets the default link
|
|
*/
|
|
static void php_ii_set_default_link(int id TSRMLS_DC)
|
|
{
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
static void php_ii_globals_init(zend_ii_globals *ii_globals)
|
|
{
|
|
ii_globals->num_persistent = 0;
|
|
}
|
|
|
|
/* Module initialization
|
|
*/
|
|
PHP_MINIT_FUNCTION(ii)
|
|
{
|
|
IIAPI_INITPARM initParm;
|
|
|
|
ZEND_INIT_MODULE_GLOBALS(ii, php_ii_globals_init, NULL);
|
|
REGISTER_INI_ENTRIES();
|
|
|
|
le_ii_link = zend_register_list_destructors_ex(php_close_ii_link, NULL, "ingres", module_number);
|
|
le_ii_plink = zend_register_list_destructors_ex(_clean_ii_plink, _close_ii_plink, "ingres persistent", module_number);
|
|
|
|
/* Constants registration */
|
|
REGISTER_LONG_CONSTANT("INGRES_ASSOC", II_ASSOC, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("INGRES_NUM", II_NUM, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("INGRES_BOTH", II_BOTH, CONST_CS | CONST_PERSISTENT);
|
|
|
|
/* Ingres api initialization */
|
|
initParm.in_timeout = -1; /* timeout in ms, -1 = no timeout */
|
|
initParm.in_version = IIAPI_VERSION_1; /* api version used */
|
|
|
|
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)
|
|
{
|
|
IIG(default_link) = -1;
|
|
IIG(num_links) = IIG(num_persistent);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* End of request
|
|
*/
|
|
PHP_RSHUTDOWN_FUNCTION(ii)
|
|
{
|
|
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];
|
|
|
|
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) {
|
|
TSRMLS_FETCH();
|
|
php_error_docref(NULL TSRMLS_CC, 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 */
|
|
TSRMLS_FETCH();
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Server or API error - no error message available");
|
|
} else {
|
|
IIAPI_GETEINFOPARM getEInfoParm;
|
|
TSRMLS_FETCH();
|
|
|
|
getEInfoParm.ge_errorHandle = genParm->gp_errorHandle;
|
|
IIapi_getErrorInfo(&getEInfoParm);
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Server or API error : %s", getEInfoParm.ge_message);
|
|
php_error_docref(NULL TSRMLS_CC, 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;
|
|
|
|
/* Setting db, user and pass according to sql_safe_mode, parameters and/or default values */
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (PG(sql_safe_mode)) { /* sql_safe_mode */
|
|
|
|
if (argc > 0) {
|
|
php_error_docref(NULL TSRMLS_CC, 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("ingres___") - 1;
|
|
hashed_details = (char *) emalloc(hashed_details_length + 1);
|
|
sprintf(hashed_details, "Ingres__%s_", user);
|
|
|
|
} else { /* non-sql_safe_mode */
|
|
|
|
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 = Z_STRVAL_PP(password);
|
|
/* Fall-through. */
|
|
|
|
case 2:
|
|
convert_to_string_ex(username);
|
|
user = Z_STRVAL_PP(username);
|
|
/* Fall-through. */
|
|
|
|
case 1:
|
|
convert_to_string_ex(database);
|
|
db = Z_STRVAL_PP(database);
|
|
/* Fall-through. */
|
|
|
|
case 0:
|
|
break;
|
|
}
|
|
|
|
hashed_details_length = sizeof("ingres___") - 1 +
|
|
strlen(SAFE_STRING(db)) +
|
|
strlen(SAFE_STRING(user)) +
|
|
strlen(SAFE_STRING(pass));
|
|
|
|
hashed_details = (char *) emalloc(hashed_details_length + 1);
|
|
sprintf(hashed_details, "Ingres_%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_docref(NULL TSRMLS_CC, 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_docref(NULL TSRMLS_CC, 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_docref(NULL TSRMLS_CC, 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_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to connect to database (%s)", db);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
link = (II_LINK *) malloc(sizeof(II_LINK));
|
|
link->connHandle = connParm.co_connHandle;
|
|
link->tranHandle = NULL;
|
|
link->stmtHandle = NULL;
|
|
link->fieldCount = 0;
|
|
link->descriptor = NULL;
|
|
link->autocommit = 0;
|
|
|
|
/* hash it up */
|
|
Z_TYPE(new_le) = 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_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to hash (%s)", hashed_details);
|
|
free(link);
|
|
efree(hashed_details);
|
|
RETURN_FALSE;
|
|
}
|
|
IIG(num_persistent)++;
|
|
IIG(num_links)++;
|
|
|
|
} else { /* already open persistent connection */
|
|
|
|
if (Z_TYPE_P(le) != 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;
|
|
|
|
/* Unfortunetaly NO !!!*/
|
|
/* Ingres api doesn't reconnect */
|
|
/* Have to reconnect if cleaning function has flagged link as broken */
|
|
if (link->connHandle == NULL) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,"Ingres II: Broken link (%s),reconnect", db);
|
|
|
|
/* Recreate 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; /* 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_docref(NULL TSRMLS_CC, E_WARNING,"Ingres II: Unable to connect to database (%s)", db);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
link->connHandle = connParm.co_connHandle;
|
|
link->tranHandle = NULL;
|
|
link->stmtHandle = NULL;
|
|
link->fieldCount = 0;
|
|
link->descriptor = NULL;
|
|
link->autocommit = 0;
|
|
}
|
|
}
|
|
|
|
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 (Z_TYPE_P(index_ptr) != 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);
|
|
Z_LVAL_P(return_value) = (int) link;
|
|
|
|
php_ii_set_default_link((int) link TSRMLS_CC);
|
|
|
|
Z_TYPE_P(return_value) = 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_docref(NULL TSRMLS_CC, 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_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to connect to database (%s)", db);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
link = (II_LINK *) malloc(sizeof(II_LINK));
|
|
link->connHandle = connParm.co_connHandle;
|
|
link->tranHandle = NULL;
|
|
link->stmtHandle = NULL;
|
|
link->fieldCount = 0;
|
|
link->descriptor = NULL;
|
|
link->autocommit = 0;
|
|
|
|
/* add it to the list */
|
|
ZEND_REGISTER_RESOURCE(return_value, link, le_ii_link);
|
|
|
|
/* add it to the hash */
|
|
new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
|
|
Z_TYPE(new_index_ptr) = 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_docref(NULL TSRMLS_CC, E_WARNING, "Ingres II: Unable to hash (%s)", hashed_details);
|
|
free(link);
|
|
efree(hashed_details);
|
|
RETURN_FALSE;
|
|
}
|
|
IIG(num_links)++;
|
|
}
|
|
|
|
efree(hashed_details);
|
|
php_ii_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
|
|
}
|
|
|
|
/* {{{ proto resource ingres_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(ingres_connect)
|
|
{
|
|
php_ii_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource ingres_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(ingres_pconnect)
|
|
{
|
|
php_ii_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool ingres_close([resource link])
|
|
Close an Ingres II database connection */
|
|
PHP_FUNCTION(ingres_close)
|
|
{
|
|
zval **link = NULL;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
|
|
switch (ZEND_NUM_ARGS()) {
|
|
case 0:
|
|
link_id = IIG(default_link);
|
|
break;
|
|
|
|
case 1:
|
|
if (zend_get_parameters_ex(1, &link) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
link_id = -1;
|
|
break;
|
|
|
|
default:
|
|
WRONG_PARAM_COUNT;
|
|
break;
|
|
}
|
|
|
|
ZEND_FETCH_RESOURCE2(ii_link, II_LINK *, link, link_id, "Ingres II Link", le_ii_link, le_ii_plink);
|
|
|
|
/* Call the clean function synchronously here */
|
|
/* Otherwise we have to wait for request shutdown */
|
|
/* This way we can reuse the link in the same script */
|
|
_ai_clean_ii_plink(ii_link TSRMLS_CC);
|
|
|
|
if (link_id == -1) { /* explicit resource number */
|
|
zend_list_delete(Z_RESVAL_PP(link));
|
|
}
|
|
|
|
if (link_id != -1 || (link && Z_RESVAL_PP(link) == IIG(default_link))) {
|
|
zend_list_delete(IIG(default_link));
|
|
IIG(default_link) = -1;
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool ingres_query(string query [, resource link])
|
|
Send a SQL query to Ingres II */
|
|
/* This should go into the documentation */
|
|
/* Unsupported query types:
|
|
- close
|
|
- commit
|
|
- connect
|
|
- disconnect
|
|
- get dbevent
|
|
- prepare to commit
|
|
- rollback
|
|
- savepoint
|
|
- set autocommit
|
|
- <all cursor related queries>
|
|
(look for dedicated functions instead) */
|
|
PHP_FUNCTION(ingres_query)
|
|
{
|
|
zval **query, **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
IIAPI_QUERYPARM queryParm;
|
|
IIAPI_GETDESCRPARM getDescrParm;
|
|
|
|
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);
|
|
}
|
|
|
|
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_docref(NULL TSRMLS_CC, 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 ingres_num_rows([resource link])
|
|
Return the number of rows affected/returned by the last query */
|
|
|
|
/* Warning : don't call ingres_num_rows() before ingres_fetch_xx(),
|
|
or ingres_fetch_xx() wouldn't find any data */
|
|
PHP_FUNCTION(ingres_num_rows)
|
|
{
|
|
zval **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
IIAPI_GETQINFOPARM getQInfoParm;
|
|
|
|
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);
|
|
}
|
|
|
|
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 ingres_num_fields([resource link])
|
|
Return the number of fields returned by the last query */
|
|
PHP_FUNCTION(ingres_num_fields)
|
|
{
|
|
zval **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
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:
|
|
fun_name = "foobar";
|
|
break;
|
|
}
|
|
php_error_docref(NULL TSRMLS_CC, 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 TSRMLS_CC);
|
|
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_docref(NULL TSRMLS_CC, 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 TSRMLS_DC)
|
|
{
|
|
if (index < 1 || index > ii_link->fieldCount) {
|
|
php_error_docref(NULL TSRMLS_CC, 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 ingres_field_name(int index [, resource link])
|
|
Return the name of a field in a query result index must be >0 and <= ingres_num_fields() */
|
|
PHP_FUNCTION(ingres_field_name)
|
|
{
|
|
php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_NAME);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string ingres_field_type(int index [, resource link])
|
|
Return the type of a field in a query result index must be >0 and <= ingres_num_fields() */
|
|
PHP_FUNCTION(ingres_field_type)
|
|
{
|
|
php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_TYPE);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string ingres_field_nullable(int index [, resource link])
|
|
Return true if the field is nullable and false otherwise index must be >0 and <= ingres_num_fields() */
|
|
PHP_FUNCTION(ingres_field_nullable)
|
|
{
|
|
php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_NULLABLE);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string ingres_field_length(int index [, resource link])
|
|
Return the length of a field in a query result index must be >0 and <= ingres_num_fields() */
|
|
PHP_FUNCTION(ingres_field_length)
|
|
{
|
|
php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_LENGTH);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string ingres_field_precision(int index [, resource link])
|
|
Return the precision of a field in a query result index must be >0 and <= ingres_num_fields() */
|
|
PHP_FUNCTION(ingres_field_precision)
|
|
{
|
|
php_ii_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, II_FIELD_INFO_PRECISION);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string ingres_field_scale(int index [, resource link])
|
|
Return the scale of a field in a query result index must be >0 and <= ingres_num_fields() */
|
|
PHP_FUNCTION(ingres_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 = 0;
|
|
long value_long = 0;
|
|
char *value_char_p;
|
|
int len, should_copy, correct_length;
|
|
|
|
/* array initialization */
|
|
array_init(return_value);
|
|
|
|
/* 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 *) safe_emalloc(j, sizeof(IIAPI_DATAVALUE), 0);
|
|
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_docref(NULL TSRMLS_CC, 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_null(return_value, i + k - 1);
|
|
}
|
|
if (result_type & II_ASSOC) {
|
|
add_assoc_null(return_value, php_ii_field_name(ii_link, i + k - 1 TSRMLS_CC));
|
|
}
|
|
|
|
} 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_docref(NULL TSRMLS_CC, 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 TSRMLS_CC), 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_docref(NULL TSRMLS_CC, 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 TSRMLS_CC), 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 TSRMLS_CC);
|
|
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 TSRMLS_CC), 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_docref(NULL TSRMLS_CC, 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 ingres_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(ingres_fetch_array)
|
|
{
|
|
zval **result_type, **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
|
|
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);
|
|
}
|
|
|
|
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 ingres_fetch_row([resource link])
|
|
Fetch a row of result into an enumerated array */
|
|
PHP_FUNCTION(ingres_fetch_row)
|
|
{
|
|
zval **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
|
|
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);
|
|
}
|
|
|
|
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 ingres_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(ingres_fetch_object)
|
|
{
|
|
zval **result_type, **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
|
|
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);
|
|
}
|
|
|
|
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 ingres_rollback([resource link])
|
|
Roll back a transaction */
|
|
PHP_FUNCTION(ingres_rollback)
|
|
{
|
|
zval **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
|
|
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 TSRMLS_CC)) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool ingres_commit([resource link])
|
|
Commit a transaction */
|
|
PHP_FUNCTION(ingres_commit)
|
|
{
|
|
zval **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
IIAPI_COMMITPARM commitParm;
|
|
|
|
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_docref(NULL TSRMLS_CC, 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;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool ingres_autocommit([resource link])
|
|
Switch autocommit on or off */
|
|
PHP_FUNCTION(ingres_autocommit)
|
|
{
|
|
zval **link;
|
|
int argc;
|
|
int link_id = -1;
|
|
II_LINK *ii_link;
|
|
IIAPI_AUTOPARM autoParm;
|
|
|
|
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);
|
|
|
|
autoParm.ac_genParm.gp_callback = NULL;
|
|
autoParm.ac_genParm.gp_closure = NULL;
|
|
autoParm.ac_connHandle = ii_link->connHandle;
|
|
autoParm.ac_tranHandle = ii_link->tranHandle;
|
|
|
|
IIapi_autocommit(&autoParm);
|
|
ii_sync(&(autoParm.ac_genParm));
|
|
|
|
if (ii_success(&(autoParm.ac_genParm)) == II_FAIL) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ii_link->autocommit = (ii_link->autocommit ? 0 : 1);
|
|
ii_link->tranHandle = autoParm.ac_tranHandle;
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
#endif /* HAVE_II */
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
* vim<600: sw=4 ts=4
|
|
*/
|