Welcome, PDO_IDS, to the PECL repository.

This commit is contained in:
Dan Scott
2005-10-18 01:07:35 +00:00
parent d04519116a
commit 50e4db6a8f
10 changed files with 2162 additions and 0 deletions

2
CREDITS Executable file
View File

@@ -0,0 +1,2 @@
pdo_informix
Rick McGuire, Krishna Raman

0
EXPERIMENTAL Executable file
View File

18
Makefile.frag Executable file
View File

@@ -0,0 +1,18 @@
#OVERALL_TARGET += $(srcdir)/preprocessed_file.c
#$(srcdir)/ifx.c: $(srcdir)/preprocessed_file.ec $(builddir)/pdo_informix.a
# (if test -d $(INFORMIXDIR); then \
# THREADLIB=POSIX $(INFORMIXDIR)/bin/esql -e $(IFX_ESQL_FLAGS) $(srcdir)/ifx.ec; mv preprocessed_file.c $@; \
# THREADLIB=POSIX $(INFORMIXDIR)/bin/esql -e $(IFX_ESQL_FLAGS) $(srcdir)/ifx.ec; \
# mv preprocessed_file.c $@ || true; \
# else \
# touch $@; \
# fi)
$(builddir)/pdo_informix.a:
$(LIBTOOL) --mode=link $(CC) $(IFX_LIBOBJS) -o $@
realclean: distclean
rm -rf acinclude.m4 aclocal.m4 autom4te.cache build config.guess config.h config.h.in config.nice config.sub configure configure.in .deps include install-sh ltmain.sh Makefile.global missing mkinstalldirs modules
.PHONY: realclean

128
config.m4 Executable file
View File

@@ -0,0 +1,128 @@
dnl $Id$
dnl config.m4 for extension pdo_informix
dnl vim:et:sw=2:ts=2:
if test "$PHP_PDO" != "no"; then
PHP_ARG_WITH(pdo-informix, for Informix driver for PDO,
[ --with-pdo-informix[=DIR] Include PDO Informix support, DIR is the base
Informix install directory, defaults to ${INFORMIXDIR:-nothing}.])
if test "$PHP_PDO_INFORMIX" != "no"; then
if test "$INFORMIXDIR" = ""; then
AC_MSG_ERROR([INFORMIXDIR environment variable is not set.])
fi
AC_MSG_CHECKING([for PDO includes])
if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
pdo_inc_path=$abs_srcdir/ext
elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
pdo_inc_path=$abs_srcdir/ext
elif test -f $prefix/include/php/ext/pdo/php_pdo_driver.h; then
pdo_inc_path=$prefix/include/php/ext
else
AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
fi
AC_MSG_RESULT($pdo_inc_path)
dnl Don't forget to add additional source files here
php_pdo_informix_sources_core="pdo_informix.c informix_driver.c informix_statement.c"
if test "$PHP_PDO_INFORMIX" != "no"; then
AC_MSG_CHECKING([for includes and libraries])
PHP_ADD_INCLUDE($INFORMIXDIR/incl/cli)
PHP_ADD_INCLUDE($INFORMIXDIR/incl/esql)
dnl PHP_ADD_INCLUDE($INFORMIXDIR/incl/<whatever include directory you need>)
PHP_ADD_LIBPATH($INFORMIXDIR/lib, PDO_INFORMIX_SHARED_LIBADD)
PHP_ADD_LIBPATH($INFORMIXDIR/lib/cli, PDO_INFORMIX_SHARED_LIBADD)
PHP_ADD_LIBPATH($INFORMIXDIR/lib/esql, PDO_INFORMIX_SHARED_LIBADD)
else
if test "$PHP_INFORMIX" != "$INFORMIXDIR"; then
AC_MSG_ERROR([Specified Informix base install directory is different than your INFORMIXDIR environment variable.])
fi
PHP_ADD_INCLUDE($INFORMIXDIR/incl/cli)
PHP_ADD_INCLUDE($INFORMIXDIR/incl/esql)
dnl PHP_ADD_INCLUDE($INFORMIXDIR/incl/<whatever include directory you need>)
PHP_ADD_LIBPATH($PHP_INFORMIX/lib, PDO_INFORMIX_SHARED_LIBADD)
PHP_ADD_LIBPATH($PHP_INFORMIX/lib/cli, PDO_INFORMIX_SHARED_LIBADD)
PHP_ADD_LIBPATH($PHP_INFORMIX/lib/esql, PDO_INFORMIX_SHARED_LIBADD)
fi
dnl Check if thread safety flags are needed
if test "$enable_experimental_zts" = "yes"; then
IFX_ESQL_FLAGS="-thread"
CPPFLAGS="$CPPFLAGS -DIFX_THREAD"
else
IFX_ESQL_FLAGS=""
fi
IFX_LIBS=`THREADLIB=POSIX $INFORMIXDIR/bin/esql $IFX_ESQL_FLAGS -libs`
IFX_LIBS=`echo $IFX_LIBS | sed -e 's/Libraries to be used://g' -e 's/esql: error -55923: No source or object file\.//g'`
dnl Seems to get rid of newlines.
dnl According to Perls DBD-Informix, might contain these strings.
case "$host_alias" in
*aix*)
CPPFLAGS="$CPPFLAGS -D__H_LOCALEDEF";;
esac
AC_MSG_CHECKING([Informix version])
IFX_VERSION=[`$INFORMIXDIR/bin/esql -V | grep "ESQL Version" | sed -ne '1 s/\(.*\)ESQL Version \([0-9]*\)\.\([0-9]*\).*/\2\3/p'`]
AC_MSG_RESULT($IFX_VERSION)
AC_DEFINE_UNQUOTED(IFX_VERSION, $IFX_VERSION, [ ])
if test $IFX_VERSION -ge "900"; then
AC_DEFINE(HAVE_IFX_IUS,1,[ ])
dnl IFX_ESQL_FLAGS="$IFX_ESQL_FLAGS -EDHAVE_IFX_IUS"
dnl else
dnl IFX_ESQL_FLAGS="$IFX_ESQL_FLAGS -EUHAVE_IFX_IUS"
fi
PHP_NEW_EXTENSION(pdo_informix, $php_pdo_informix_sources_core, $ext_shared,,-I$pdo_inc_path)
PHP_ADD_MAKEFILE_FRAGMENT
PHP_ADD_LIBRARY_DEFER(ifcli, 1, PDO_INFORMIX_SHARED_LIBADD)
PHP_ADD_LIBRARY_DEFER(ifdmr, 1, PDO_INFORMIX_SHARED_LIBADD)
for i in $IFX_LIBS; do
case "$i" in
*.o)
IFX_LIBOBJS="$IFX_LIBOBJS $i"
PHP_ADD_LIBPATH($ext_builddir, PDO_INFORMIX_SHARED_LIBADD)
dnl PHP_ADD_LIBRARY_DEFER(pdo_informix, 1, PDO_INFORMIX_SHARED_LIBADD)
;;
-lm)
;;
-lc)
;;
-l*)
lib=`echo $i | cut -c 3-`
PHP_ADD_LIBRARY_DEFER($lib, 1, PDO_INFORMIX_SHARED_LIBADD)
;;
*.a)
case "`uname -s 2>/dev/null`" in
UnixWare | SCO_SV | UNIX_SV)
DLIBS="$DLIBS $i"
;;
*)
ac_dir="`echo $i|sed 's#[^/]*$##;s#\/$##'`"
ac_lib="`echo $i|sed 's#^/.*/lib##g;s#\.a##g'`"
DLIBS="$DLIBS -L$ac_dir -l$ac_lib"
;;
esac
;;
esac
done
PHP_SUBST(PDO_INFORMIX_SHARED_LIBADD)
PHP_SUBST(INFORMIXDIR)
PHP_SUBST(IFX_LIBOBJS)
PHP_SUBST(IFX_ESQL_FLAGS)
fi
fi

13
config.w32 Executable file
View File

@@ -0,0 +1,13 @@
// $Id$
// vim:ft=javascript
// If your extension references something external, use ARG_WITH
// ARG_WITH("pdo_informix", "for pdo_informix support", "no");
// Otherwise, use ARG_ENABLE
// ARG_ENABLE("pdo_informix", "enable pdo_informix support", "no");
if (PHP_PDO_INFORMIX != "no") {
EXTENSION("pdo_informix", "pdo_informix.c");
}

593
informix_driver.c Executable file
View File

@@ -0,0 +1,593 @@
/*
+----------------------------------------------------------------------+
| (C) Copyright IBM Corporation 2005. |
+----------------------------------------------------------------------+
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you |
| may not use this file except in compliance with the License. You may |
| obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
+----------------------------------------------------------------------+
| Authors: Rick McGuire, Krishna Raman |
| |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "pdo/php_pdo.h"
#include "pdo/php_pdo_driver.h"
#include "php_pdo_informix.h"
#include "php_pdo_informix_int.h"
#include "zend_exceptions.h"
#include <stdio.h>
extern struct pdo_stmt_methods informix_stmt_methods;
extern int informix_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC);
// allocate and initialize the driver_data portion of a
// PDOStatement object.
static int dbh_new_stmt_data(pdo_dbh_t* dbh, pdo_stmt_t *stmt TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
stmt_handle *stmt_res = (stmt_handle *)emalloc(sizeof(stmt_handle));
check_allocation(stmt_res, "dbh_new_stmt_data", "Unable to allocate stmt driver data");
memset(stmt_res, '\0', sizeof(stmt_handle));
stmt_res->columns = NULL;
// attach to the statement
stmt->driver_data = stmt_res;
stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
return TRUE;
}
// prepare a statement for execution.
static int dbh_prepare_stmt(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *stmt_string, long stmt_len, zval *driver_options TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
int rc;
// in case we need to convert the statement for positional syntax
int converted_len = 0;
stmt_res->converted_statement = NULL;
// the statement passed in to us at this point is the raw statement the programmer
// specified. If the statement is using named parameters (e.g., ":salary", we can't
// process this directly. Fortunately, PDO has a utility function that will
// munge the SQL statement into the form we require and do mappings from named to
// positional parameters.
// this is necessary...it tells the parser what we require
stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
rc = pdo_parse_params(stmt, (char *)stmt_string, stmt_len, &stmt_res->converted_statement, &converted_len TSRMLS_CC);
// if the query needed reformatting, a new statement string has been passed back
// to us. We're responsible for freeing this when we're done.
if (rc == 1)
{
stmt_string = stmt_res->converted_statement;
stmt_len = converted_len;
}
// a negative return indicates there was an error. The error_code information
// in the statement contains the reason.
else if (rc == -1)
{
// copy the error information
RAISE_IFX_STMT_ERROR(stmt->error_code, "pdo_parse_params", "Invalid SQL statement");
// this failed...error cleanup will happen later.
return FALSE;
}
/* alloc handle and return only if it errors */
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
check_stmt_error(rc, "SQLAllocHandle");
// now see if the cursor type has been explicitly specified.
stmt_res->cursor_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY TSRMLS_CC);
// the default is just sequential access. If something else has been specified, we need to make this
// scrollable.
if (stmt_res->cursor_type != PDO_CURSOR_FWDONLY)
{
// set the statement attribute
rc = SQLSetStmtAttr(stmt_res->hstmt, SQL_ATTR_CURSOR_TYPE, (void *)SQL_CURSOR_DYNAMIC, 0);
check_stmt_error(rc, "SQLSetStmtAttr");
}
// Prepare the stmt.
rc = SQLPrepare((SQLHSTMT)stmt_res->hstmt, (SQLCHAR*)stmt_string, stmt_len);
check_stmt_error(rc, "SQLPrepare");
// we can get rid of the stmt copy now
if (stmt_res->converted_statement != NULL)
{
efree(stmt_res->converted_statement);
stmt_res->converted_statement = NULL;
}
SQLSMALLINT param_count;
rc = SQLNumResultCols((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT*)&param_count);
check_stmt_error(rc, "SQLNumResultCols");
// we're responsible for setting the column_count for the PDO driver.
stmt->column_count = param_count;
// attach the methods...we are now live, so errors will no longer immediately
// force cleanup of the stmt driver-specific storage.
stmt->methods = &informix_stmt_methods;
return TRUE;
}
// debugging routine for printing out failure information.
static void current_error_state(pdo_dbh_t *dbh)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
printf("Handling error %s (%s[%ld] at %s:%d)\n",
conn_res->error_data.err_msg, // an associated message
conn_res->error_data.failure_name, // the routine name
conn_res->error_data.sqlcode, // native error code of the failure
conn_res->error_data.filename, // source file of the reported error
conn_res->error_data.lineno); // location of the reported error
}
// fetch the suppliemental error material
static int informix_handle_fetch_error(
pdo_dbh_t *dbh,
pdo_stmt_t *stmt,
zval *info
TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
char suppliment[512];
sprintf(suppliment, "%s (%s[%ld] at %s:%d)",
conn_res->error_data.err_msg, // an associated message
conn_res->error_data.failure_name, // the routine name
conn_res->error_data.sqlcode, // native error code of the failure
conn_res->error_data.filename, // source file of the reported error
conn_res->error_data.lineno); // location of the reported error
// now add the error information. These need to be added in a specific order
add_next_index_long(info, conn_res->error_data.sqlcode);
add_next_index_string(info, suppliment, 1);
return TRUE;
}
// NB. The handle closer is used for PDO dtor purposes, but we also use this for error
// cleanup if we need to throw an exception while creating the connection. In that case, the
// closer is not automatically called by PDO, so we need to force cleanup.
static int informix_handle_closer(
pdo_dbh_t *dbh
TSRMLS_DC)
{
conn_handle *conn_res;
conn_res = (conn_handle *)dbh->driver_data;
// an error can occur at many stages of setup, so we need to check the validity of
// each bit as we unwind.
if (conn_res != NULL)
{
// did we get at least as far as creating the environment?
if (conn_res->henv != SQL_NULL_HANDLE)
{
// if we have a handle for the connection, we have more stuff to clean up
if (conn_res->hdbc != SQL_NULL_HANDLE)
{
// roll back the transaction if this hasn't been committed yet.
// there's no point in checking for errors here...PDO won't process
// and of the failures even if they happen.
if (dbh->auto_commit == 0)
{
SQLEndTran(SQL_HANDLE_DBC, (SQLHDBC)conn_res->hdbc, SQL_ROLLBACK);
}
SQLDisconnect((SQLHDBC)conn_res->hdbc);
SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc);
}
// and finally the handle
SQLFreeHandle(SQL_HANDLE_ENV, conn_res->henv);
}
// now free the driver data
pefree(conn_res, dbh->is_persistent);
dbh->driver_data = NULL;
}
return TRUE;
}
// prepare a statement for execution.
static int informix_handle_preparer(
pdo_dbh_t *dbh,
const char *sql,
long sql_len,
pdo_stmt_t *stmt,
zval *driver_options
TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
// allocate new driver_data structure
if (dbh_new_stmt_data(dbh, stmt) == TRUE)
{
/* Allocates the stmt handle */
/* Prepares the statement */
/* returns the stat_handle back to the calling function */
return dbh_prepare_stmt(dbh, stmt, sql, sql_len, driver_options);
}
return FALSE;
}
// directly execute an SQL statement.
static long informix_handle_doer(
pdo_dbh_t *dbh,
const char *sql,
long sql_len
TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
SQLHANDLE hstmt;
// get a statement handle
int rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &hstmt);
check_dbh_error(rc, "SQLAllocHandle");
rc = SQLExecDirect(hstmt, (SQLCHAR *)sql, sql_len);
if (rc == SQL_ERROR)
{
// NB...we raise the error before freeing the handle so that
// we catch the proper error record.
raise_sql_error(dbh, NULL, hstmt, SQL_HANDLE_STMT,
"SQLExecDirect", __FILE__, __LINE__ TSRMLS_CC);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
// things are a bit overloaded here...we're supposed to return a count of the affected
// rows, but -1 indicates an error occurred.
return -1;
}
// we need to update the number of affected rows.
SQLINTEGER rowCount;
rc = SQLRowCount(hstmt, &rowCount);
if (rc == SQL_ERROR)
{
// NB...we raise the error before freeing the handle so that
// we catch the proper error record.
raise_sql_error(dbh, NULL, hstmt, SQL_HANDLE_STMT,
"SQLRowCount", __FILE__, __LINE__ TSRMLS_CC);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return -1;
}
// this is a one-shot deal, so make sure we free the statement handle
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return rowCount;
}
// start a new transaction
static int informix_handle_begin( pdo_dbh_t *dbh TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
int rc = SQLSetConnectAttr(conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS);
check_dbh_error(rc, "SQLSetConnectAttr");
return TRUE;
}
static int informix_handle_commit(
pdo_dbh_t *dbh
TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
int rc = SQLEndTran(SQL_HANDLE_DBC, conn_res->hdbc, SQL_COMMIT);
check_dbh_error(rc, "SQLEndTran");
rc = SQLSetConnectAttr(conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS);
check_dbh_error(rc, "SQLSetConnectAttr");
return TRUE;
}
static int informix_handle_rollback(
pdo_dbh_t *dbh
TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
int rc = SQLEndTran(SQL_HANDLE_DBC, conn_res->hdbc, SQL_ROLLBACK);
check_dbh_error(rc, "SQLEndTran");
rc = SQLSetConnectAttr(conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS);
check_dbh_error(rc, "SQLSetConnectAttr");
return TRUE;
}
// get the driver attributes. We return the autocommit and
// version information.
static int informix_handle_get_attribute(
pdo_dbh_t *dbh,
long attr,
zval *return_value
TSRMLS_DC)
{
switch (attr)
{
case PDO_ATTR_CLIENT_VERSION:
ZVAL_STRING(return_value, "Informix 1.0", 1);
return TRUE;
case PDO_ATTR_AUTOCOMMIT:
ZVAL_BOOL(return_value, dbh->auto_commit);
return TRUE;
}
return FALSE;
}
// the following is not supported by IFX.
#ifdef __PDO_DB2__
static int informix_handle_check_liveness(
pdo_dbh_t *dbh
TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
SQLINTEGER dead_flag;
SQLINTEGER length;
int rc = SQLGetConnectAttr(conn_res->hdbc, SQL_ATTR_CONNECTION_DEAD,
(SQLPOINTER)&dead_flag, sizeof(dead_flag), &length);
// this will qualify as a failed liveness check
if (rc == SQL_ERROR)
{
RAISE_DBH_ERROR("SQLGetConnectAttr");
return FAILURE;
}
// return the state from the query
return dead_flag == SQL_CD_FALSE ? SUCCESS : FAILURE;
}
#endif
static struct pdo_dbh_methods informix_dbh_methods =
{
informix_handle_closer,
informix_handle_preparer,
informix_handle_doer,
NULL, // only required if using PLACEHOLDER_NONE
informix_handle_begin,
informix_handle_commit,
informix_handle_rollback,
NULL, // set attribute
NULL, // last ID
informix_handle_fetch_error,
informix_handle_get_attribute,
#ifdef __PDO_DB2__
informix_handle_check_liveness,
#else
NULL, // check_liveness
#endif
NULL // get_driver_methods
};
// handle the business of creating a connection.
static int dbh_connect(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
{
int rc = 0;
// allocate our driver data control block. If this is a persistent connection,
// we need to allocate this from persistent storage.
conn_handle *conn_res = (conn_handle *)pemalloc(sizeof(conn_handle), dbh->is_persistent);
check_allocation(conn_res, "dbh_connect", "Unable to allocate driver data");
// clear, and hook up to the PDO data structure.
memset((void *) conn_res, '\0', sizeof(conn_handle));
dbh->driver_data = conn_res;
// we need an environment to use for a base
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &conn_res->henv);
check_dbh_error(rc, "SQLAllocHandle");
// and we're using the OBDC version 3 style interface
rc = SQLSetEnvAttr((SQLHENV)conn_res->henv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
check_dbh_error(rc, "SQLSetEnvAttr");
// now an actual connection handle
rc = SQLAllocHandle( SQL_HANDLE_DBC, conn_res->henv, &(conn_res->hdbc));
check_dbh_error(rc, "SQLAllocHandle");
// if we're in auto commit mode, set the connection attribute.
if (dbh->auto_commit != 0)
{
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS);
check_dbh_error(rc, "SQLSetConnectAttr");
}
//NB: We don't have any specific driver options we support at this time, so
// we don't need to do any option parsing.
// If the string contains a =, then we need to use SQLDriverConnect to make the
// connection. This may require reform var_dump($rows);atting the DSN string to include a userid and
// password.
if (strchr(dbh->data_source, '=') != NULL )
{
// first check to see if we have a user name
if (dbh->username != NULL && strlen(dbh->username) > 0)
{
//ok, one was given...however, the DSN may already contain UID information,
// so check first.
if (strstr(dbh->data_source, ";uid=") == NULL && strstr(dbh->data_source, ";UID=") == NULL)
{
int dsn_length = strlen(dbh->data_source) + strlen(dbh->username) + strlen(dbh->password) + sizeof(";UID=;PWD=;") + 1;
char *new_dsn = pemalloc(dsn_length, dbh->is_persistent);
check_allocation(new_dsn, "dbh_connect", "unable to allocate DSN string");
sprintf(new_dsn, "%s;UID=%s;PWD=%s;", dbh->data_source, dbh->username, dbh->password);
// now replace the DSN with a properly formatted one.
pefree((void *)dbh->data_source, dbh->is_persistent);
dbh->data_source = new_dsn;
}
}
// and finally try to connect
rc = SQLDriverConnect((SQLHDBC)conn_res->hdbc, (SQLHWND)NULL,
(SQLCHAR*)dbh->data_source, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT );
check_dbh_error(rc, "SQLDriverConnect");
}
else
{
// no connection options specified, we can just connect with the name, userid, and
// password as given. var_dump($rows);
rc = SQLConnect( (SQLHDBC)conn_res->hdbc, (SQLCHAR *)dbh->data_source,
(SQLSMALLINT)dbh->data_source_len, (SQLCHAR *)dbh->username, (SQLSMALLINT)strlen(dbh->username),
(SQLCHAR *)dbh->password, (SQLSMALLINT)strlen(dbh->password));
check_dbh_error(rc, "SQLConnect");
}
dbh->native_case = PDO_CASE_LOWER;
dbh->desired_case = PDO_CASE_UPPER;
// this is now live! all error handling goes through normal mechanisms.
dbh->methods = &informix_dbh_methods;
dbh->alloc_own_columns = 1;
return TRUE;
}
// main routine called to create a connection. The dbh structure is allocated
// for us, and we attached a driver-specific control block to the PDO allocated one,
static int informix_handle_factory(
pdo_dbh_t *dbh,
zval *driver_options
TSRMLS_DC)
{
// go do the connection
return dbh_connect( dbh, driver_options);
}
pdo_driver_t pdo_informix_driver =
{
PDO_DRIVER_HEADER(informix),
informix_handle_factory
};
// common error handling path for final disposition of an error.
static void process_pdo_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC)
{
// current_error_state(dbh);
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
strcpy(dbh->error_code, conn_res->error_data.sql_state);
if (stmt != NULL)
{
// what this a error in the stmt constructor?
if (stmt->methods == NULL)
{
// make sure we do any required cleanup.
informix_stmt_dtor(stmt TSRMLS_CC);
}
strcpy(stmt->error_code, conn_res->error_data.sql_state);
}
// if we got an error very early, we need to throw an exception rather than
// use the PDO error reporting.
if (dbh->methods == NULL)
{
// if we're not fully initialized, we need to force cleanup ourselves.
informix_handle_closer(dbh TSRMLS_CC);
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE=%s, %s: %d %s",
conn_res->error_data.sql_state, conn_res->error_data.failure_name,
conn_res->error_data.sqlcode, conn_res->error_data.err_msg);
}
}
// handle an error return from an SQL call. The error information from the
// call is saved in our error record.
void raise_sql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, SQLHANDLE handle,
SQLSMALLINT hType, char *tag, char *file, int line TSRMLS_DC)
{
SQLSMALLINT length;
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
conn_res->error_data.failure_name = tag;
conn_res->error_data.filename = file;
conn_res->error_data.lineno = line;
SQLGetDiagRec(hType, handle, 1, (SQLCHAR *)&(conn_res->error_data.sql_state),
&(conn_res->error_data.sqlcode), (SQLCHAR *)&(conn_res->error_data.err_msg),
SQL_MAX_MESSAGE_LENGTH, &length );
// the error message is not returned null terminated.
conn_res->error_data.err_msg[length] = '\0';
// now go tell PDO about this problem
process_pdo_error(dbh, stmt TSRMLS_DC);
}
// raise a driver-detected error. This is a faked-SQL type error, using a provided
// sqlstate and message info.
void raise_informix_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *state, char *tag,
char *message, char *file, int line TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
conn_res->error_data.failure_name = tag;
conn_res->error_data.filename = file;
conn_res->error_data.lineno = line;
strcpy(conn_res->error_data.err_msg, message);
strcpy(conn_res->error_data.sql_state, state);
conn_res->error_data.sqlcode = 1; // just give a non-zero code state.
// now go tell PDO about this problem
process_pdo_error(dbh, stmt TSRMLS_DC);
}
// raise an error in a connection context. This ensures we use the
// connection handle for retrieving error information.
void raise_dbh_error(pdo_dbh_t *dbh, char *tag, char *file, int line TSRMLS_DC)
{
conn_handle *conn_res = (conn_handle *)dbh->driver_data;
raise_sql_error(dbh, NULL, conn_res->hdbc, SQL_HANDLE_DBC, tag, file, line TSRMLS_DC);
}
// raise an error in a statement context. This ensures we use the correct
// handle for retrieving the diag record, as well as forcing stmt-related
// cleanup.
void raise_stmt_error(pdo_stmt_t *stmt, char *tag, char *file, int line TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// if we're in the middle of execution when an error was detected, make sure we cancel
if (stmt_res->executing)
{
// cancel the statement
SQLCancel(stmt_res->hstmt);
// make sure we release execution-related storage.
if (stmt_res->lob_buffer != NULL)
{
efree(stmt_res->lob_buffer);
stmt_res->lob_buffer == NULL;
}
if (stmt_res->converted_statement != NULL)
{
efree(stmt_res->converted_statement);
stmt_res->converted_statement == NULL;
}
stmt_res->executing = 0;
}
raise_sql_error(stmt->dbh, stmt, stmt_res->hstmt, SQL_HANDLE_STMT, tag, file, line TSRMLS_DC);
}

976
informix_statement.c Executable file
View File

@@ -0,0 +1,976 @@
/*
+----------------------------------------------------------------------+
| (C) Copyright IBM Corporation 2005. |
+----------------------------------------------------------------------+
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you |
| may not use this file except in compliance with the License. You may |
| obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
+----------------------------------------------------------------------+
| Authors: Rick McGuire, Krishna Raman |
| |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "pdo/php_pdo.h"
#include "pdo/php_pdo_driver.h"
#include "php_pdo_informix.h"
#include "php_pdo_informix_int.h"
// clear up our column descriptors. This is done either from
// the statement constructors or whenever we traverse from one
// result set to the next.
static void stmt_free_column_descriptors(pdo_stmt_t *stmt TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
if (stmt_res->columns != NULL)
{
int i;
// see if any of the columns have attached storage too.
for (i = 0; i < stmt->column_count; i++)
{
// was this a string form? We have an allocated string
// buffer that also needs releasing.
if (stmt_res->columns[i].returned_type == PDO_PARAM_STR)
{
efree(stmt_res->columns[i].data.str_val);
}
}
// free the entire column list.
efree(stmt_res->columns);
stmt_res->columns = NULL;
}
}
// cleanup any driver-allocated control blocks attached to a statement
// instance. This cleans up the driver_data control block, as
// well as any temporary allocations used during execution.
void stmt_cleanup(pdo_stmt_t *stmt)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
if (stmt_res != NULL)
{
if (stmt_res->converted_statement != NULL)
{
efree(stmt_res->converted_statement);
}
if (stmt_res->lob_buffer != NULL)
{
efree(stmt_res->lob_buffer);
}
// free any descriptors we're keeping active
stmt_free_column_descriptors(stmt);
efree(stmt_res);
}
stmt->driver_data = NULL;
}
// get the parameter description information for a positional bound parameter.
static int stmt_get_parameter_info(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC)
{
param_node *param_res = (param_node *)param->driver_data;
// do we have the parameter information yet?
if (param_res == NULL)
{
// allocate a new one and attach to the PDO param structure
param_res = (param_node *)emalloc(sizeof(param_node));
check_stmt_allocation(param_res, "stmt_get_parameter", "Unable to allocate parameter driver data");
// get the statement specifics
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// NB: The PDO parameter numbers are origin zero, but the SQLDescribeParam()
// ones start with 1.
int rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, param->paramno + 1, &param_res->data_type,
&param_res->param_size, &param_res->scale, &param_res->nullable);
check_stmt_error(rc, "SQLDescribeParam");
// only attach this if we succeed
param->driver_data = param_res;
// but see if we need to alter this for binary forms or
// can optimize numerics a little.
switch (param_res->data_type)
{
// the binary forms need to be transferred as binary data,
// not as char data.
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
param_res->ctype = SQL_C_BINARY;
break;
// numeric forms we can map directly to a long
// int value
case SQL_SMALLINT:
case SQL_INTEGER:
param_res->ctype = SQL_C_LONG;
break;
// everything else will transfer as binary
default:
// by default, we transfer as character data
param_res->ctype = SQL_C_CHAR;
break;
}
}
return TRUE;
}
// bind a statement parameter to the PHP value supplying or receiving the
// parameter data.
int stmt_bind_parameter(pdo_stmt_t *stmt, struct pdo_bound_param_data *curr TSRMLS_DC)
{
int rc;
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// make sure we have current description information.
if (stmt_get_parameter_info(stmt, curr TSRMLS_CC) == FALSE)
{
return FALSE;
}
param_node *param_res = (param_node *)curr->driver_data;
// now figure out the parameter type so we can tell the database code
// how to handle this.
SQLSMALLINT inputOutputType;
// this is rare, really only used for stored procedures.
if (curr->param_type & PDO_PARAM_INPUT_OUTPUT > 0)
{
inputOutputType = SQL_PARAM_INPUT_OUTPUT;
}
// if this is a non-positive length, we can't assign a value,
// so this is by definition an INPUT param.
else if (curr->max_value_len <= 0)
{
inputOutputType = SQL_PARAM_INPUT;
}
// everything else is output.
else
{
inputOutputType = SQL_PARAM_OUTPUT;
}
// now do the actual binding, which is controlled by the
// PDO supplied type.
switch (PDO_PARAM_TYPE(curr->param_type))
{
// not implemented yet
case PDO_PARAM_STMT:
RAISE_IFX_STMT_ERROR("IM001", "param_hook", "Driver does not support statement parameters");
return FALSE;
// this is a long value for PHP
case PDO_PARAM_INT:
// if the parameter type is a numeric type, we'll bind this directly,
if (param_res->ctype == SQL_C_LONG)
{
// force this to be a real boolean value
convert_to_long(curr->parameter);
rc = SQLBindParameter(stmt_res->hstmt, curr->paramno + 1,
inputOutputType, SQL_C_LONG, param_res->data_type, param_res->param_size,
param_res->scale, &((curr->parameter)->value.lval), 0, NULL);
check_stmt_error(rc, "SQLBindParameter");
return TRUE;
}
// NOTE: We fall through from above if there is a type mismatch.
// a string value (very common)
case PDO_PARAM_BOOL:
case PDO_PARAM_STR:
// if we're capable of handling an integer value, but PDO
// is telling us string, then change this now.
if (param_res->ctype == SQL_C_LONG)
{
// change this to a character type
param_res->ctype = SQL_C_CHAR;
}
if( Z_TYPE_P(curr->parameter) == IS_NULL ){
param_res->ctype = SQL_C_DEFAULT;
param_res->param_size = 0;
param_res->scale = 0;
curr->max_value_len = 0;
param_res->transfer_length = SQL_NULL_DATA;
rc = SQLBindParameter(stmt_res->hstmt, curr->paramno + 1,
inputOutputType, param_res->ctype, param_res->data_type, param_res->param_size,
param_res->scale, NULL , curr->max_value_len <= 0 ? 0 : curr->max_value_len,
&param_res->transfer_length);
check_stmt_error(rc, "SQLBindParameter");
}else{
// force this to be a real string value
convert_to_string(curr->parameter);
// set the transfer length to zero now...this gets update
// at EXEC_PRE time.
param_res->transfer_length = 0;
// now we need to make sure the string buffer is large enough
// to receive a new value if this is an output or in/out parameter
if (inputOutputType != SQL_PARAM_INPUT && curr->max_value_len > Z_STRLEN_P(curr->parameter))
{
// reallocate this to the new size
Z_STRVAL_P(curr->parameter) = erealloc(Z_STRVAL_P(curr->parameter), curr->max_value_len + 1);
check_stmt_allocation(Z_STRVAL_P(curr->parameter), "stmt_bind_parameter", "Unable to allocate bound parameter");
}
rc = SQLBindParameter(stmt_res->hstmt, curr->paramno + 1,
inputOutputType, param_res->ctype, param_res->data_type, param_res->param_size,
param_res->scale, Z_STRVAL_P(curr->parameter), curr->max_value_len <= 0 ? 0 : curr->max_value_len,
&param_res->transfer_length);
check_stmt_error(rc, "SQLBindParameter");
}
return TRUE;
// this is either a string, or, if the length is zero,
// then this is a pointer to a PHP stream.
case PDO_PARAM_LOB:
if (inputOutputType != SQL_PARAM_INPUT)
{
inputOutputType = SQL_PARAM_INPUT;
//RAISE_IFX_STMT_ERROR( "HY105" , "SQLBindParameter" , "PDO_PARAM_LOB parameters can only be used for input" );
//return FALSE;
}
// have we bound a LOB to a long type for some reason?
if (param_res->ctype == SQL_C_LONG)
{
// transfer this as character data.
param_res->ctype = SQL_C_CHAR;
}
// indicate we're going to transfer the data at exec time.
param_res->transfer_length = SQL_DATA_AT_EXEC;
// we can't bind LOBs at this point...we process all of this at execute time.
// however, we set the value data to the PDO binding control block and
// set the SQL_DATA_AT_EXEC value to cause it to prompt us for the data at
// execute time. The pointer is recoverable at that time by using
// SQLParamData(), and we can then process the request.
rc = SQLBindParameter(stmt_res->hstmt, curr->paramno + 1,
inputOutputType, param_res->ctype, param_res->data_type, param_res->param_size,
param_res->scale, curr, 0, &param_res->transfer_length);
check_stmt_error(rc, "SQLBindParameter");
return TRUE;
// this is an unknown type
default:
RAISE_IFX_STMT_ERROR( "IM001" , "SQLBindParameter" , "Unknown parameter type" );
return FALSE;
}
return TRUE;
}
// handle the pre-execution phase for bound parameters.
static int stmt_parameter_pre_execute(pdo_stmt_t *stmt, struct pdo_bound_param_data *curr TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
param_node *param_res = (param_node *)curr->driver_data;
// now we need to prepare the parameter binding information
// for execution. If this is a LOB, then we need to ensure
// the LOB data is going to be available and make sure
// the binding is tagged to provide the data at exec time.
if (PDO_PARAM_TYPE(curr->param_type) == PDO_PARAM_LOB)
{
// if the LOB data is a stream, we need to make sure it is
// really there.
if (Z_TYPE_P(curr->parameter) == IS_RESOURCE)
{
php_stream *stm;
php_stream_statbuf sb;
// make sure we have a stream to work with
php_stream_from_zval_no_verify(stm, &curr->parameter);
if (stm == NULL)
{
RAISE_IFX_STMT_ERROR( "HY000" , "SQLBindParameter" , "PDO_PARAM_LOB file stream is invalid");
}
// now see if we can retrieve length information from the stream
if (php_stream_stat(stm, &sb) == 0)
{
// yes, we're able to give the statement some hints about the size.
param_res->transfer_length = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
}
else
{
// still unknown...we'll have to do everything at execute size.
param_res->transfer_length = SQL_LEN_DATA_AT_EXEC(0);
}
}
else
{
// convert this to a string value now. We bound the data pointer to our
// parameter descriptor, so we can't just supply this directly yet, but we
// can at least give the size hint information.
convert_to_string(curr->parameter);
param_res->transfer_length = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(curr->parameter));
}
}
else
{
if( Z_TYPE_P(curr->parameter) != IS_NULL ){
// if we're processing this as string or binary data, then
// directly update the length to the real value.
if (param_res->ctype == SQL_C_LONG)
{
// make sure this is a long value
convert_to_long(curr->parameter);
}
else
{
// make sure this is a string value...it might have been
// changed between the bind and the execute
convert_to_string(curr->parameter);
param_res->transfer_length = Z_STRLEN_P(curr->parameter);
}
}
}
return TRUE;
}
// post-execution bound parameter handling.
static int stmt_parameter_post_execute(pdo_stmt_t *stmt, struct pdo_bound_param_data *curr TSRMLS_DC)
{
param_node *param_res = (param_node *)curr->driver_data;
// if the type of the parameter is a string, we need to update the
// string length and make sure that these are null terminated.
// Values returned from the DB are just copied directly into the bound
// locations, so we need to update the PHP control blocks so that the
// data is processed correctly.
if (Z_TYPE_P(curr->parameter) == IS_STRING)
{
if( param_res->transfer_length == SQL_NULL_DATA ){
ZVAL_NULL(curr->parameter);
}else if(param_res->transfer_length == 0){
ZVAL_EMPTY_STRING(curr->parameter);
}else{
Z_STRLEN_P(curr->parameter) = param_res->transfer_length;
Z_STRVAL_P(curr->parameter)[param_res->transfer_length] = '\0';
}
}
return TRUE;
}
// bind a column to an internally allocated buffer location.
static int stmt_bind_column(pdo_stmt_t *stmt, int colno TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// access the information for this column
column_data *col_res = &stmt_res->columns[colno];
char tmp_name[BUFSIZ];
// get the column descriptor information
int rc = SQLDescribeCol((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT)(colno + 1 ),
tmp_name, BUFSIZ, &col_res->namelen, &col_res->data_type, &col_res->data_size, &col_res->scale, &col_res->nullable);
check_stmt_error(rc, "SQLDescribeCol");
// make sure we get a name properly. If the name is too long for our
// buffer (which in theory should never happen), allocate a longer one
// and ask for the information again.
if (col_res->namelen <= 0 )
{
col_res->name = estrdup("");
check_stmt_allocation(col_res->name, "stmt_bind_column", "Unable to allocate column name");
}
else if (col_res->namelen >= BUFSIZ )
{
/* column name is longer than BUFSIZ*/
col_res->name = emalloc(col_res->namelen + 1);
check_stmt_allocation(col_res->name, "stmt_bind_column", "Unable to allocate column name");
rc = SQLDescribeCol((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT)(colno + 1 ),
col_res->name, BUFSIZ, &col_res->namelen, &col_res->data_type,
&col_res->data_size, &col_res->scale, &col_res->nullable);
check_stmt_error(rc, "SQLDescribeCol");
}
else
{
col_res->name = estrdup(tmp_name);
check_stmt_allocation(col_res->name, "stmt_bind_column", "Unable to allocate column name");
}
struct pdo_column_data *col = &stmt->columns[colno];
// copy the information back into the PDO control block. Note that
// PDO will release the name information, so we don't have to.
col->name = col_res->name;
col->namelen = col_res->namelen;
col->maxlen = col_res->data_size;
col->precision = col_res->scale;
// now process the column types
switch (col_res->data_type)
{
// the PDO test cases are written to expect everything to be returned
// as a string value. The following code works, but it forces the values
// to PDO ints, and the test driver doesn't like that.
#if 0
// this is a long value for PHP
case SQL_SMALLINT:
case SQL_INTEGER:
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(colno + 1),
SQL_C_LONG, &col_res->data.l_val, sizeof(col_res->data.l_val),
(SQLINTEGER *)(&col_res->out_length));
// these are all returned as long values
col_res->returned_type = PDO_PARAM_INT;
col->param_type = PDO_PARAM_INT;
break;
#endif
// a form we need to force into a string value...this includes any unknown types
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_TYPE_TIME:
case SQL_TYPE_TIMESTAMP:
case SQL_BIGINT:
case SQL_REAL:
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_DECIMAL:
case SQL_NUMERIC:
default:
{
int in_length = col_res->data_size + 1;
col_res->data.str_val = (char *)emalloc(in_length);
check_stmt_allocation(col_res->data.str_val, "stmt_bind_column", "Unable to allocate column buffer");
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(colno + 1),
SQL_C_CHAR, col_res->data.str_val, in_length,
(SQLINTEGER *)(&col_res->out_length));
col_res->returned_type = PDO_PARAM_STR;
col->param_type = PDO_PARAM_STR;
}
#if 0
// a blob form....we'll process this at fetch time by doing
// a SQLGetData() call.
case SQL_CLOB:
case SQL_BLOB:
// we're going to need to do getdata calls to retrieve these
col_res->out_length = 0;
// and this is returned as a string too
col_res->returned_type = PDO_PARAM_STR;
break;
#endif
}
return TRUE;
}
// allocate a set of internal column descriptors for a statement.
static int stmt_allocate_column_descriptors(pdo_stmt_t *stmt TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
SQLSMALLINT nResultCols = 0;
// not sure
int rc = SQLNumResultCols((SQLHSTMT)stmt_res->hstmt, &nResultCols);
check_stmt_error(rc, "SQLNumResultCols");
// make sure we set the count in the PDO stmt structure so the driver
// knows how many columns we're dealing with.
stmt->column_count = nResultCols;
// allocate the column descriptors now. We'll bind each column individually before the
// first fetch. The binding process will allocate any additional buffers we might need
// for the data.
stmt_res->columns = (column_data *)ecalloc(sizeof(column_data), stmt->column_count);
check_stmt_allocation(stmt_res->columns, "stmt_allocate_column_descriptors", "Unable to allocate column descriptor tables");
memset(stmt_res->columns, '\0', sizeof(column_data) * stmt->column_count);
return TRUE;
}
// this is also used for error cleanup for errors that occur while the stmt is still
// half constructed.
int informix_stmt_dtor( pdo_stmt_t *stmt TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
if (stmt_res != NULL)
{
if (stmt_res->hstmt != SQL_NULL_HANDLE)
{
// if we've done some work, we need to clean up.
if (stmt->executed)
{
// cancel anything we have pending at this point
SQLCancel(stmt_res->hstmt);
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt_res->hstmt);
stmt_res->hstmt = SQL_NULL_HANDLE;
}
// release an control blocks we have attached to this statement
stmt_cleanup(stmt);
}
return TRUE;
}
// execute a PDOStatement. Used for both the PDOStatement::execute() method
// as well as the PDO:query() method.
static int informix_stmt_executer(
pdo_stmt_t *stmt
TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// if this statement has already been executed, then we need to
// cancel the previous execution before doing this again.
if (stmt->executed)
{
int rc = SQLFreeStmt( stmt_res->hstmt , SQL_CLOSE );
check_stmt_error(rc, "SQLFreeStmt");
}
// we're executing now...this tells error handling to Cancel if there's an error.
stmt_res->executing = 1;
stmt_res->lob_buffer = NULL;
// Execute the statement. All parameters should be bound at this point,
// but we might need to pump data in for some of the parameters.
int rc = SQLExecute((SQLHSTMT)stmt_res->hstmt);
check_stmt_error(rc, "SQLExecute");
// now check if we have indirectly bound parameters. If we do, then we
// need to push the data for those parameters into the processing pipe.
while (rc == SQL_NEED_DATA)
{
struct pdo_bound_param_data *param;
// get the associated parameter data. The bind process should have
// stored a pointer to the parameter control block, so we identify
// which one needs data from that.
rc = SQLParamData(stmt_res->hstmt, (SQLPOINTER *)&param);
check_stmt_error(rc, "SQLParamData");
if (rc == SQL_NEED_DATA)
{
// OK, we have a LOB. This is either in string form, in which case we can supply it
// directly, or is a PHP stream. If it is a stream, then the type is IS_RESOURCE, and
// we need to pump the data in a buffer at a time.
if (Z_TYPE_P(param->parameter) != IS_RESOURCE)
{
rc = SQLPutData(stmt_res->hstmt, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
check_stmt_error(rc, "SQLPutData");
}
else
{
// the LOB is a stream. This better still be good, else we
// can't supply the data.
php_stream *stm = NULL;
int len;
php_stream_from_zval_no_verify(stm, &(param->parameter));
if (!stm)
{
RAISE_IFX_STMT_ERROR("HY000", "execute", "Input parameter LOB is no longer a valid stream");
return FALSE;
}
// allocate a buffer if we haven't prior to this
if (stmt_res->lob_buffer == NULL)
{
stmt_res->lob_buffer = emalloc(LOB_BUFFER_SIZE);
check_stmt_allocation(stmt_res->lob_buffer, "stmt_execute", "Unable to allocate parameter data buffer");
}
// read a buffer at a time and push into the execution pipe.
for (;;)
{
len = php_stream_read(stm, stmt_res->lob_buffer, LOB_BUFFER_SIZE);
if (len == 0)
{
break;
}
// add the buffer
rc = SQLPutData(stmt_res->hstmt, stmt_res->lob_buffer, len);
check_stmt_error(rc, "SQLPutData");
}
}
rc = SQLParamData(stmt_res->hstmt, (SQLPOINTER *)&param);
check_stmt_error(rc, "SQLParamData");
}
}
// free any LOB buffer we might have
if (stmt_res->lob_buffer != NULL)
{
efree(stmt_res->lob_buffer);
}
// now set the rowcount field in the statement. This will be the
// number of rows affected by the SQL statement, not the number of
// rows in the result set.
SQLINTEGER rowCount;
rc = SQLRowCount(stmt_res->hstmt, &rowCount);
check_stmt_error(rc, "SQLRowCount");
// store the affected rows information.
stmt->row_count = rowCount;
// is this the first time we've executed this statement?
if (!stmt->executed)
{
if (stmt_allocate_column_descriptors(stmt) == FALSE)
{
return FALSE;
}
}
// we can turn off the cleanup flag now
stmt_res->executing = 0;
return TRUE;
}
// fetch the next row of the result set.
static int informix_stmt_fetcher(
pdo_stmt_t *stmt,
enum pdo_fetch_orientation ori,
long offset
TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// by default, we're just fetching the next one
SQLSMALLINT direction = SQL_FETCH_NEXT;
// convert the PDO orientation information to the
// SQL one.
switch (ori)
{
case PDO_FETCH_ORI_NEXT:
direction = SQL_FETCH_NEXT;
break;
case PDO_FETCH_ORI_PRIOR:
direction = SQL_FETCH_PRIOR;
break;
case PDO_FETCH_ORI_FIRST:
direction = SQL_FETCH_FIRST;
break;
case PDO_FETCH_ORI_LAST:
direction = SQL_FETCH_LAST;
break;
case PDO_FETCH_ORI_ABS:
direction = SQL_FETCH_ABSOLUTE;
break;
case PDO_FETCH_ORI_REL:
direction = SQL_FETCH_RELATIVE;
break;
}
// go fetch it.
int rc = SQLFetchScroll(stmt_res->hstmt, direction, (SQLINTEGER)offset);
check_stmt_error(rc, "SQLFetchScroll");
// The fetcher() routine has an overloaded return value. A false return
// can indicate either an error or the end of the row data.
if (rc == SQL_NO_DATA)
{
// if we are scrolling forward, then close the cursor to release
// resources tied up by this statement.
if (stmt_res->cursor_type == PDO_CURSOR_FWDONLY)
{
SQLCloseCursor(stmt_res->hstmt);
}
return FALSE;
}
return TRUE;
}
// process the various bound parameter events.
static int informix_stmt_param_hook(
pdo_stmt_t *stmt,
struct pdo_bound_param_data *param,
enum pdo_param_event event_type
TSRMLS_DC)
{
// we get called for both parameters and bound columns. We
// only need to process the parameters
if (param->is_param)
{
switch (event_type)
{
case PDO_PARAM_EVT_ALLOC:
break;
case PDO_PARAM_EVT_FREE:
// during the alloc event, we attached some
// driver specific data. We need to free this now.
if (param->driver_data != NULL)
{
efree(param->driver_data);
param->driver_data = NULL;
}
break;
case PDO_PARAM_EVT_EXEC_PRE:
// we're allocating a bound parameter, go do the binding
stmt_bind_parameter(stmt, param);
return stmt_parameter_pre_execute(stmt, param);
case PDO_PARAM_EVT_EXEC_POST:
return stmt_parameter_post_execute(stmt, param);
// parameters aren't processed at the fetch phase.
case PDO_PARAM_EVT_FETCH_PRE:
case PDO_PARAM_EVT_FETCH_POST:
break;
}
}
return TRUE;
}
// describe a column for the PDO driver.
static int informix_stmt_describer(
pdo_stmt_t *stmt,
int colno
TSRMLS_DC)
{
// get the descriptor information and bind to the column location
return stmt_bind_column(stmt, colno);
}
// fetch the data for a specific column. This should be sitting in our
// allocated buffer already, and easy to return.
static int informix_stmt_get_col(
pdo_stmt_t *stmt,
int colno,
char **ptr,
unsigned long *len,
int *caller_frees
TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// access our look aside data
column_data *col_res = &stmt_res->columns[colno];
// see if this is a null value
if (col_res->out_length == SQL_NULL_DATA)
{
// return this as a real null
*ptr == NULL;
*len = 0;
}
// string type...very common
else if (col_res->returned_type == PDO_PARAM_STR)
{
// set the info
*ptr = col_res->data.str_val;
*len = col_res->out_length;
}
// binary numeric form
else
{
*ptr = (char *)&col_res->data.l_val;
*len = col_res->out_length;
}
return TRUE;
}
// step to the next result set of the query.
static int informix_stmt_next_rowset(
pdo_stmt_t *stmt
TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// now get the next result set. This has the side effect
// of cleaning up the current cursor, if it exists.
int rc = SQLMoreResults(stmt_res->hstmt);
// we don't raise errors here. A success return codes
// signals we have more result sets to process, so we
// set everything up to read that info. Otherwise, we just
// signal the main driver we're finished.
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
{
return FALSE;
}
// the next result set may have different column information, so
// we need to clear out our existing set.
stmt_free_column_descriptors(stmt);
// now allocate a new set of column descriptors
if (stmt_allocate_column_descriptors(stmt) == FALSE)
{
return FALSE;
}
// more results to process
return TRUE;
}
// return all of the meta data information that makes sense for
// this database driver.
static int informix_stmt_get_column_meta(
pdo_stmt_t *stmt,
long colno,
zval *return_value
TSRMLS_DC)
{
if (colno >= stmt->column_count)
{
RAISE_IFX_STMT_ERROR("HY097", "getColumnMeta", "Column number out of range");
return FAILURE;
}
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// access our look aside data
column_data *col_res = &stmt_res->columns[colno];
// make sure the return value is initialized as an array.
array_init(return_value);
add_assoc_long(return_value, "scale", col_res->scale);
#define ATTRIBUTEBUFFERSIZE 256
char attribute_buffer[ATTRIBUTEBUFFERSIZE];
SQLSMALLINT length;
SQLINTEGER numericAttribute;
// see if we can retrieve the table name
if (SQLColAttribute(stmt_res->hstmt, colno + 1, SQL_DESC_BASE_TABLE_NAME,
(SQLPOINTER)attribute_buffer, ATTRIBUTEBUFFERSIZE, &length,
(SQLPOINTER)&numericAttribute) != SQL_ERROR)
{
// most of the time, this seems to return a null string. only
// return this if we have something real.
if (length > 0)
{
add_assoc_stringl(return_value, "table", attribute_buffer, length, 1);
}
}
// see if we can retrieve the type name
if (SQLColAttribute(stmt_res->hstmt, colno + 1, SQL_DESC_TYPE_NAME,
(SQLPOINTER)attribute_buffer, ATTRIBUTEBUFFERSIZE, &length,
(SQLPOINTER)&numericAttribute) != SQL_ERROR)
{
add_assoc_stringl(return_value, "native_type", attribute_buffer, length, 1);
}
zval *flags;
MAKE_STD_ZVAL(flags);
array_init(flags);
add_assoc_bool(flags, "not_null", !col_res->nullable);
// see if we can retrieve the unsigned attribute
if (SQLColAttribute(stmt_res->hstmt, colno + 1, SQL_DESC_UNSIGNED,
(SQLPOINTER)attribute_buffer, ATTRIBUTEBUFFERSIZE, &length,
(SQLPOINTER)&numericAttribute) != SQL_ERROR)
{
add_assoc_bool(flags, "unsigned", numericAttribute == SQL_TRUE);
}
// see if we can retrieve the autoincrement attribute
if (SQLColAttribute(stmt_res->hstmt, colno + 1, SQL_DESC_AUTO_UNIQUE_VALUE,
(SQLPOINTER)attribute_buffer, ATTRIBUTEBUFFERSIZE, &length,
(SQLPOINTER)&numericAttribute) != SQL_ERROR)
{
add_assoc_bool(flags, "auto_increment", numericAttribute == SQL_TRUE);
}
// add the flags to the result bundle.
add_assoc_zval(return_value, "flags", flags);
return SUCCESS;
}
#define CURSOR_NAME_BUFFER_LENGTH 256
// get driver specific attributes. We only support CURSOR_NAME.
static int informix_stmt_get_attribute(
pdo_stmt_t *stmt,
long attr,
zval *return_value
TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
// anything we can't handle is an error
switch (attr)
{
case PDO_ATTR_CURSOR_NAME:
{
char buffer[CURSOR_NAME_BUFFER_LENGTH];
SQLSMALLINT length;
int rc = SQLGetCursorName(stmt_res->hstmt, buffer,
CURSOR_NAME_BUFFER_LENGTH, &length);
check_stmt_error(rc, "SQLGetCursorName");
// this is a string value
ZVAL_STRINGL(return_value, buffer, length, 1);
return TRUE;
}
// unknown attribute
default:
{
// raise a driver error, and give the special -1 return.
RAISE_IFX_STMT_ERROR("IM001", "getAttribute", "Unknown attribute");
return -1; // the -1 return does not raise an error immediately.
}
}
}
// set a driver-specific attribute. We only support CURSOR_NAME.
static int informix_stmt_set_attribute(
pdo_stmt_t *stmt,
long attr,
zval *value
TSRMLS_DC)
{
stmt_handle *stmt_res = (stmt_handle *)stmt->driver_data;
switch (attr)
{
case PDO_ATTR_CURSOR_NAME:
{
// we need to force this to a string value
convert_to_string(value);
// set the cursor value
int rc = SQLSetCursorName(stmt_res->hstmt,
Z_STRVAL_P(value), Z_STRLEN_P(value));
check_stmt_error(rc, "SQLSetCursorName");
return TRUE;
}
default:
{
// raise a driver error, and give the special -1 return.
RAISE_IFX_STMT_ERROR("IM001", "getAttribute", "Unknown attribute");
return -1; // the -1 return does not raise an error immediately.
}
}
}
struct pdo_stmt_methods informix_stmt_methods =
{
informix_stmt_dtor,
informix_stmt_executer,
informix_stmt_fetcher,
informix_stmt_describer,
informix_stmt_get_col,
informix_stmt_param_hook,
informix_stmt_set_attribute,
informix_stmt_get_attribute,
informix_stmt_get_column_meta,
informix_stmt_next_rowset
};

195
pdo_informix.c Executable file
View File

@@ -0,0 +1,195 @@
/*
+----------------------------------------------------------------------+
| (C) Copyright IBM Corporation 2005. |
+----------------------------------------------------------------------+
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you |
| may not use this file except in compliance with the License. You may |
| obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
+----------------------------------------------------------------------+
| Authors: Rick McGuire, Krishna Raman |
| |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "pdo/php_pdo_driver.h"
#include "php_pdo_informix.h"
/* If you declare any globals in php_pdo_informix.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(pdo_informix)
*/
/* True global resources - no need for thread safety here */
static int le_pdo_informix;
extern pdo_driver_t pdo_informix_driver; // the registration table
/* {{{ pdo_informix_functions[]
*
* Every user visible function must have an entry in pdo_informix_functions[].
*/
function_entry pdo_informix_functions[] = {
PHP_FE(confirm_pdo_informix_compiled, NULL) /* For testing, remove later. */
{
NULL, NULL, NULL
} /* Must be the last line in pdo_informix_functions[] */
};
/* }}} */
/* {{{ pdo_informix_module_entry
*/
zend_module_entry pdo_informix_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"pdo_informix",
pdo_informix_functions,
PHP_MINIT(pdo_informix),
PHP_MSHUTDOWN(pdo_informix),
PHP_RINIT(pdo_informix), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(pdo_informix), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(pdo_informix),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_PDO_INFORMIX
ZEND_GET_MODULE(pdo_informix)
#endif
/* {{{ PHP_INI
*/
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("pdo_informix.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_pdo_informix_globals, pdo_informix_globals)
STD_PHP_INI_ENTRY("pdo_informix.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_pdo_informix_globals, pdo_informix_globals)
PHP_INI_END()
*/
/* }}} */
/* {{{ php_pdo_informix_init_globals
*/
/* Uncomment this function if you have INI entries
static void php_pdo_informix_init_globals(zend_pdo_informix_globals *pdo_informix_globals)
{
pdo_informix_globals->global_value = 0;
pdo_informix_globals->global_string = NULL;
}
*/
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(pdo_informix)
{
/* If you have INI entries, uncomment these lines
ZEND_INIT_MODULE_GLOBALS(pdo_informix, php_pdo_informix_init_globals, NULL);
REGISTER_INI_ENTRIES();
*/
php_pdo_register_driver(&pdo_informix_driver);
return TRUE;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(pdo_informix)
{
/* uncomment this line if you have INI entries
UNREGISTER_INI_ENTRIES();
*/
php_pdo_unregister_driver(&pdo_informix_driver);
return TRUE;
}
/* }}} */
/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(pdo_informix)
{
return TRUE;
}
/* }}} */
/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION(pdo_informix)
{
return TRUE;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(pdo_informix)
{
php_info_print_table_start();
php_info_print_table_header(2, "pdo_informix support", "enabled");
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
}
/* }}} */
/* Remove the following function when you have succesfully modified config.m4
so that your module can be compiled into PHP, it exists only for testing
purposes. */
/* Every user-visible function in PHP should document itself in the source */
/* {{{ proto string confirm_pdo_informix_compiled(string arg)
Return a string to confirm that the module is compiled in */
PHP_FUNCTION(confirm_pdo_informix_compiled)
{
char *arg = NULL;
int arg_len, len;
char string[256];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FALSE)
{
return;
}
len = sprintf(string, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "pdo_informix", arg);
RETURN_STRINGL(string, len, 1);
}
/* }}} */
/* The previous line is meant for vim and emacs, so it can correctly fold and
unfold functions in source code. See the corresponding marks just before
function definition, where the functions purpose is also documented. Please
follow this convention for the convenience of others editing your code.
*/
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

83
php_pdo_informix.h Executable file
View File

@@ -0,0 +1,83 @@
/*
+----------------------------------------------------------------------+
| (C) Copyright IBM Corporation 2005. |
+----------------------------------------------------------------------+
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you |
| may not use this file except in compliance with the License. You may |
| obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
+----------------------------------------------------------------------+
| Authors: Rick McGuire, Krishna Raman |
| |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_INFORMIX_H
#define PHP_PDO_INFORMIX_H
extern zend_module_entry pdo_informix_module_entry;
#define phpext_pdo_informix_ptr &pdo_informix_module_entry
#ifdef PHP_WIN32
#define PHP_PDO_INFORMIX_API __declspec(dllexport)
#else
#define PHP_PDO_INFORMIX_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(pdo_informix);
PHP_MSHUTDOWN_FUNCTION(pdo_informix);
PHP_RINIT_FUNCTION(pdo_informix);
PHP_RSHUTDOWN_FUNCTION(pdo_informix);
PHP_MINFO_FUNCTION(pdo_informix);
PHP_FUNCTION(confirm_pdo_informix_compiled); /* For testing, remove later. */
/*
Declare any global variables you may need between the BEGIN
and END macros here:
ZEND_BEGIN_MODULE_GLOBALS(pdo_informix)
long global_value;
char *global_string;
ZEND_END_MODULE_GLOBALS(pdo_informix)
*/
/* In every utility function you add that needs to use variables
in php_pdo_informix_globals, call TSRMLS_FETCH(); after declaring other
variables used by that function, or better yet, pass in TSRMLS_CC
after the last function argument and declare your utility function
with TSRMLS_DC after the last declared argument. Always refer to
the globals in your function as PDO_INFORMIX_G(variable). You are
encouraged to rename these macros something shorter, see
examples in any other php module directory.
*/
#ifdef ZTS
#define PDO_INFORMIX_G(v) TSRMG(pdo_informix_globals_id, zend_pdo_informix_globals *, v)
#else
#define PDO_INFORMIX_G(v) (pdo_informix_globals.v)
#endif
#endif /* PHP_PDO_INFORMIX_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

154
php_pdo_informix_int.h Executable file
View File

@@ -0,0 +1,154 @@
/*
+----------------------------------------------------------------------+
| (C) Copyright IBM Corporation 2005. |
+----------------------------------------------------------------------+
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you |
| may not use this file except in compliance with the License. You may |
| obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
+----------------------------------------------------------------------+
| Authors: Rick McGuire, Krishna Raman |
| |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_INFORMIX_INT_H
#define PHP_PDO_INFORMIX_INT_H
#include "infxcli.h"
#define MAX_OPTION_LEN 10
#define MAX_ERR_MSG_LEN (SQL_MAX_MESSAGE_LENGTH + SQL_SQLSTATE_SIZE + 1)
// error handling functions and macros.
void raise_sql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, SQLHANDLE handle,
SQLSMALLINT hType, char *tag, char *file, int line TSRMLS_DC);
void raise_informix_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *state, char *tag, char *message, char *file, int line TSRMLS_DC);
void raise_dbh_error(pdo_dbh_t *dbh, char *tag, char *file, int line TSRMLS_DC);
void raise_stmt_error(pdo_stmt_t *stmt, char *tag, char *file, int line TSRMLS_DC);
int informix_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC);
#define RAISE_DBH_ERROR(tag) raise_dbh_error(dbh, tag, __FILE__, __LINE__ TSRMLS_CC)
#define RAISE_STMT_ERROR(tag) raise_stmt_error(stmt, tag, __FILE__, __LINE__ TSRMLS_CC)
#define RAISE_IFX_STMT_ERROR(state, tag, msg) raise_informix_error(stmt->dbh, stmt, state, tag, msg, __FILE__, __LINE__ TSRMLS_CC)
#define RAISE_IFX_DBH_ERROR(state, tag, msg) raise_informix_error(dbh, NULL, state, tag, msg, __FILE__, __LINE__ TSRMLS_CC)
// check for an SQL error in the context of an
// PDO method execution.
#define check_dbh_error(rc, tag) \
{ \
if ( rc == SQL_ERROR ) \
{ \
RAISE_DBH_ERROR(tag); \
return FALSE; \
} \
} \
// check for an SQL error in the context of an
// PDOStatement method execution.
#define check_stmt_error(rc, tag) \
{ \
if ( rc == SQL_ERROR ) \
{ \
RAISE_STMT_ERROR(tag); \
return FALSE; \
} \
} \
// check an allocation in the context of a PDO object.
#define check_allocation(ptr, tag, msg) \
{ \
if ((ptr) == NULL) \
{ \
RAISE_IFX_DBH_ERROR("HY001", tag, msg); \
return FALSE; \
} \
} \
// check a storage allocation for a PDOStatement
// object context.
#define check_stmt_allocation(ptr, tag, msg) \
{ \
if ((ptr) == NULL) \
{ \
RAISE_IFX_STMT_ERROR("HY001", tag, msg); \
return FALSE; \
} \
} \
typedef struct _conn_error_data
{
SQLINTEGER sqlcode; // native sql error code
char *filename; // name of the file raising the error
int lineno; // line number location of the error
char *failure_name; // the failure tag.
SQLCHAR sql_state[8]; // SQLSTATE code
char err_msg[SQL_MAX_MESSAGE_LENGTH + 1]; // error message associated with failure
} conn_error_data;
typedef struct _conn_handle_struct {
SQLHANDLE henv; // handle to the interface environment
SQLHANDLE hdbc; // the connection handle
conn_error_data error_data; // error handling information
} conn_handle;
// values used for binding fetched data
typedef union {
long l_val; // long values -- used for all int values, including bools
char *str_val; // used for string bindings
} column_data_value;
// local descriptor for column data. These mirror the
// descriptors given back to the PDO driver.
typedef struct {
char *name; // the column name
SQLSMALLINT namelen; // length of the column name
SQLSMALLINT data_type; // the database column type
enum pdo_param_type returned_type; // our returned parameter type
SQLUINTEGER data_size; // maximum size of the data
SQLSMALLINT nullable; // the nullable flag
SQLSMALLINT scale; // the scale value
SQLUINTEGER out_length; // the transfered data length. Filled in by a fetch
column_data_value data; // the transferred data
} column_data;
// size of the buffer used to read LOB streams
#define LOB_BUFFER_SIZE 8192
typedef struct _stmt_handle_struct
{
SQLHANDLE hstmt; // the statement handle associated with the stmt
int executing; // an executing state flag for error cleanup
char *converted_statement; // temporary version of the statement with parameter replacement
char *lob_buffer; // buffer used for reading in LOB parameters
column_data *columns; // the column descriptors
enum pdo_cursor_type cursor_type; // the type of cursor we support.
} stmt_handle;
// Defines the driver_data structure for caching param data
typedef struct _param_node {
SQLSMALLINT data_type; // The database data type
SQLUINTEGER param_size; // param size
SQLSMALLINT nullable; // is Nullable
SQLSMALLINT scale; // Decimal scale
SQLSMALLINT ctype; // the optimal C type for transfer
SQLINTEGER transfer_length; // the transfer length of the parameter
} param_node;
#endif