mirror of
https://github.com/php/pecl-database-pdo_informix.git
synced 2026-03-23 23:12:12 +01:00
Welcome, PDO_IDS, to the PECL repository.
This commit is contained in:
0
EXPERIMENTAL
Executable file
0
EXPERIMENTAL
Executable file
18
Makefile.frag
Executable file
18
Makefile.frag
Executable 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
128
config.m4
Executable 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
13
config.w32
Executable 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
593
informix_driver.c
Executable 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*)¶m_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
976
informix_statement.c
Executable 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, ¶m_res->data_type,
|
||||
¶m_res->param_size, ¶m_res->scale, ¶m_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,
|
||||
¶m_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,
|
||||
¶m_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, ¶m_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 *)¶m);
|
||||
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 *)¶m);
|
||||
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
195
pdo_informix.c
Executable 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
83
php_pdo_informix.h
Executable 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
154
php_pdo_informix_int.h
Executable 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
|
||||
Reference in New Issue
Block a user