summaryrefslogtreecommitdiff
path: root/ext/pdo_oci
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_oci')
-rwxr-xr-xext/pdo_oci/CREDITS2
-rw-r--r--ext/pdo_oci/EXPERIMENTAL0
-rwxr-xr-xext/pdo_oci/config.m4241
-rwxr-xr-xext/pdo_oci/config.w3246
-rw-r--r--ext/pdo_oci/oci_driver.c740
-rw-r--r--ext/pdo_oci/oci_statement.c767
-rw-r--r--ext/pdo_oci/package2.xml72
-rw-r--r--ext/pdo_oci/pdo_oci.c133
-rw-r--r--ext/pdo_oci/php_pdo_oci.h47
-rw-r--r--ext/pdo_oci/php_pdo_oci_int.h100
-rw-r--r--ext/pdo_oci/tests/bug41996.phpt20
-rw-r--r--ext/pdo_oci/tests/bug44301.phpt25
-rw-r--r--ext/pdo_oci/tests/bug46274.phpt73
-rw-r--r--ext/pdo_oci/tests/bug46274_2.phpt79
-rw-r--r--ext/pdo_oci/tests/bug57702.phpt165
-rw-r--r--ext/pdo_oci/tests/bug_33707.phpt29
-rw-r--r--ext/pdo_oci/tests/common.phpt26
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_autocommit_1.phpt64
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_autocommit_2.phpt127
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_autocommit_3.phpt51
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_case.phpt81
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_client.phpt43
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_drivername.phpt21
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_nulls_1.phpt61
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_prefetch_1.phpt37
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_prefetch_2.phpt47
-rw-r--r--ext/pdo_oci/tests/pdo_oci_attr_server.phpt40
-rw-r--r--ext/pdo_oci/tests/pdo_oci_fread_1.phpt60
-rw-r--r--ext/pdo_oci/tests/pdo_oci_quote1.phpt163
-rw-r--r--ext/pdo_oci/tests/pdo_oci_stream_1.phpt113
-rw-r--r--ext/pdo_oci/tests/pecl_bug_11345.phpt29
-rw-r--r--ext/pdo_oci/tests/pecl_bug_6364.phpt71
32 files changed, 3573 insertions, 0 deletions
diff --git a/ext/pdo_oci/CREDITS b/ext/pdo_oci/CREDITS
new file mode 100755
index 0000000..63e863a
--- /dev/null
+++ b/ext/pdo_oci/CREDITS
@@ -0,0 +1,2 @@
+Oracle (OCI) driver for PDO
+Wez Furlong
diff --git a/ext/pdo_oci/EXPERIMENTAL b/ext/pdo_oci/EXPERIMENTAL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ext/pdo_oci/EXPERIMENTAL
diff --git a/ext/pdo_oci/config.m4 b/ext/pdo_oci/config.m4
new file mode 100755
index 0000000..309bde8
--- /dev/null
+++ b/ext/pdo_oci/config.m4
@@ -0,0 +1,241 @@
+dnl $Id$
+dnl config.m4 for extension pdo_oci
+dnl vim:et:sw=2:ts=2:
+
+SUPPORTED_LIB_VERS="9.0 10.1 11.1" # This caters for all Oracle 9.x, 10.x and 11.1 installs
+AC_DEFUN([AC_PDO_OCI_VERSION],[
+ AC_MSG_CHECKING([Oracle version])
+ for OCI_VER in $SUPPORTED_LIB_VERS; do
+ if test -f $PDO_OCI_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME.$OCI_VER; then
+ PDO_OCI_VERSION="$OCI_VER"
+ fi
+ done
+ if test -z "$PDO_OCI_VERSION"; then
+ AC_MSG_ERROR([Oracle required OCI8 libraries not found under $PDO_OCI_DIR])
+ fi
+ AC_MSG_RESULT($PDO_OCI_VERSION)
+])
+
+AC_DEFUN([AC_PDO_OCI_CHECK_LIB_DIR],[
+ AC_CHECK_SIZEOF(long int, 4)
+ AC_MSG_CHECKING([if we're on a 64-bit platform])
+ if test "$ac_cv_sizeof_long_int" = "4" ; then
+ AC_MSG_RESULT([no])
+ TMP_PDO_OCI_LIB_DIR="$PDO_OCI_DIR/lib32"
+ else
+ AC_MSG_RESULT([yes])
+ TMP_PDO_OCI_LIB_DIR="$PDO_OCI_DIR/lib"
+ fi
+
+ AC_MSG_CHECKING([OCI8 libraries dir])
+ if test -d "$PDO_OCI_DIR/lib" && test ! -d "$PDO_OCI_DIR/lib32"; then
+ PDO_OCI_LIB_DIR="$PDO_OCI_DIR/lib"
+ elif test ! -d "$PDO_OCI_DIR/lib" && test -d "$PDO_OCI_DIR/lib32"; then
+ PDO_OCI_LIB_DIR="$PDO_OCI_DIR/lib32"
+ elif test -d "$PDO_OCI_DIR/lib" && test -d "$PDO_OCI_DIR/lib32"; then
+ PDO_OCI_LIB_DIR=$TMP_PDO_OCI_LIB_DIR
+ else
+ AC_MSG_ERROR([Oracle required OCI8 libraries not found])
+ fi
+ AC_MSG_RESULT($PDO_OCI_LIB_DIR)
+])
+
+PHP_ARG_WITH(pdo-oci, Oracle OCI support for PDO,
+[ --with-pdo-oci[=DIR] PDO: Oracle OCI support. DIR defaults to \$ORACLE_HOME.
+ Use --with-pdo-oci=instantclient,prefix,version
+ for an Oracle Instant Client SDK.
+ For example on Linux with 11.2 RPMs use:
+ --with-pdo-oci=instantclient,/usr,11.2
+ With 10.2 RPMs use:
+ --with-pdo-oci=instantclient,/usr,10.2.0.4])
+
+if test "$PHP_PDO_OCI" != "no"; then
+
+ if test "$PHP_PDO" = "no" && test "$ext_shared" = "no"; then
+ AC_MSG_ERROR([PDO is not enabled! Add --enable-pdo to your configure line.])
+ fi
+
+ AC_MSG_CHECKING([Oracle Install-Dir])
+ if test "$PHP_PDO_OCI" = "yes" || test -z "$PHP_PDO_OCI"; then
+ PDO_OCI_DIR=$ORACLE_HOME
+ else
+ PDO_OCI_DIR=$PHP_PDO_OCI
+ fi
+ AC_MSG_RESULT($PHP_PDO_OCI)
+
+ AC_MSG_CHECKING([if that is sane])
+ if test -z "$PDO_OCI_DIR"; then
+ AC_MSG_ERROR([
+You need to tell me where to find your Oracle Instant Client SDK, or set ORACLE_HOME.
+])
+ else
+ AC_MSG_RESULT([yes])
+ fi
+
+ if test "instantclient" = "`echo $PDO_OCI_DIR | cut -d, -f1`" ; then
+ AC_CHECK_SIZEOF(long int, 4)
+ if test "$ac_cv_sizeof_long_int" = "4" ; then
+ PDO_OCI_CLIENT_DIR="client"
+ else
+ PDO_OCI_CLIENT_DIR="client64"
+ fi
+ PDO_OCI_IC_PREFIX="`echo $PDO_OCI_DIR | cut -d, -f2`"
+ PDO_OCI_IC_VERS="`echo $PDO_OCI_DIR | cut -d, -f3`"
+ if test -n "$PDO_OCI_IC_VERS"; then
+ PDO_OCI_IC_MAJ_VER="`echo $PDO_OCI_IC_VERS | cut -d. -f1`"
+ if test "$PDO_OCI_IC_MAJ_VER" -ge 11; then
+ # From 11.1.0.7 the RPM path only has an X.Y component
+ PDO_OCI_IC_VERS="`echo $PDO_OCI_IC_VERS | cut -d. -f1-2`"
+ fi
+ fi
+ AC_MSG_CHECKING([for oci.h])
+ if test -f $PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/oci.h ; then
+ PHP_ADD_INCLUDE($PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR)
+ AC_MSG_RESULT($PDO_OCI_IC_PREFIX/include/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR)
+ elif test -f $PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/include/oci.h ; then
+ PHP_ADD_INCLUDE($PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/include)
+ AC_MSG_RESULT($PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/include)
+ elif test -f $PDO_OCI_IC_PREFIX/sdk/include/oci.h ; then
+ PHP_ADD_INCLUDE($PDO_OCI_IC_PREFIX/sdk/include)
+ AC_MSG_RESULT($PDO_OCI_IC_PREFIX/sdk/include)
+ elif test -f $PDO_OCI_IC_PREFIX/$PDO_OCI_CLIENT_DIR/include/oci.h ; then
+ PHP_ADD_INCLUDE($PDO_OCI_IC_PREFIX/$PDO_OCI_CLIENT_DIR/include)
+ AC_MSG_RESULT($PDO_OCI_IC_PREFIX/$PDO_OCI_CLIENT_DIR/include)
+ else
+ AC_MSG_ERROR([I'm too dumb to figure out where the include dir is in your Instant Client install])
+ fi
+ if test -f "$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then
+ PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX/lib/oracle/$PDO_OCI_IC_VERS/$PDO_OCI_CLIENT_DIR/lib"
+ elif test -f "$PDO_OCI_IC_PREFIX/$PDO_OCI_CLIENT_DIR/lib/libclntsh.$SHLIB_SUFFIX_NAME" ; then
+ PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX/$PDO_OCI_CLIENT_DIR/lib"
+ elif test -f "$PDO_OCI_IC_PREFIX/libclntsh.$SHLIB_SUFFIX_NAME" ; then
+ PDO_OCI_LIB_DIR="$PDO_OCI_IC_PREFIX"
+ else
+ AC_MSG_ERROR([I'm too dumb to figure out where the libraries are in your Instant Client install])
+ fi
+ PDO_OCI_VERSION="`echo $PDO_OCI_IC_VERS | cut -d. -f1-2`"
+ else
+ AC_PDO_OCI_CHECK_LIB_DIR($PDO_OCI_DIR)
+
+ if test -d "$PDO_OCI_DIR/rdbms/public"; then
+ PHP_ADD_INCLUDE($PDO_OCI_DIR/rdbms/public)
+ PDO_OCI_INCLUDES="$PDO_OCI_INCLUDES -I$PDO_OCI_DIR/rdbms/public"
+ fi
+ if test -d "$PDO_OCI_DIR/rdbms/demo"; then
+ PHP_ADD_INCLUDE($PDO_OCI_DIR/rdbms/demo)
+ PDO_OCI_INCLUDES="$PDO_OCI_INCLUDES -I$PDO_OCI_DIR/rdbms/demo"
+ fi
+ if test -d "$PDO_OCI_DIR/network/public"; then
+ PHP_ADD_INCLUDE($PDO_OCI_DIR/network/public)
+ PDO_OCI_INCLUDES="$PDO_OCI_INCLUDES -I$PDO_OCI_DIR/network/public"
+ fi
+ if test -d "$PDO_OCI_DIR/plsql/public"; then
+ PHP_ADD_INCLUDE($PDO_OCI_DIR/plsql/public)
+ PDO_OCI_INCLUDES="$PDO_OCI_INCLUDES -I$PDO_OCI_DIR/plsql/public"
+ fi
+ if test -d "$PDO_OCI_DIR/include"; then
+ PHP_ADD_INCLUDE($PDO_OCI_DIR/include)
+ PDO_OCI_INCLUDES="$PDO_OCI_INCLUDES -I$PDO_OCI_DIR/include"
+ fi
+
+ if test -f "$PDO_OCI_LIB_DIR/sysliblist"; then
+ PHP_EVAL_LIBLINE(`cat $PDO_OCI_LIB_DIR/sysliblist`, PDO_OCI_SYSLIB)
+ elif test -f "$PDO_OCI_DIR/rdbms/lib/sysliblist"; then
+ PHP_EVAL_LIBLINE(`cat $PDO_OCI_DIR/rdbms/lib/sysliblist`, PDO_OCI_SYSLIB)
+ fi
+ AC_PDO_OCI_VERSION($PDO_OCI_DIR)
+ fi
+
+ case $PDO_OCI_VERSION in
+ 9.0|10.1|10.2|11.1|11.2)
+ PHP_ADD_LIBRARY(clntsh, 1, PDO_OCI_SHARED_LIBADD)
+ ;;
+
+ *)
+ AC_MSG_ERROR(Unsupported Oracle version $PDO_OCI_VERSION)
+ ;;
+ esac
+
+ PHP_ADD_LIBPATH($PDO_OCI_LIB_DIR, PDO_OCI_SHARED_LIBADD)
+
+ PHP_CHECK_LIBRARY(clntsh, OCIEnvCreate,
+ [
+ AC_DEFINE(HAVE_OCIENVCREATE,1,[ ])
+ ], [], [
+ -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
+ ])
+
+ PHP_CHECK_LIBRARY(clntsh, OCIEnvNlsCreate,
+ [
+ AC_DEFINE(HAVE_OCIENVNLSCREATE,1,[ ])
+ ], [], [
+ -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
+ ])
+
+ dnl
+ dnl Check if we need to add -locijdbc8
+ dnl
+ PHP_CHECK_LIBRARY(clntsh, OCILobIsTemporary,
+ [
+ AC_DEFINE(HAVE_OCILOBISTEMPORARY,1,[ ])
+ ], [
+ PHP_CHECK_LIBRARY(ocijdbc8, OCILobIsTemporary,
+ [
+ PHP_ADD_LIBRARY(ocijdbc8, 1, PDO_OCI_SHARED_LIBADD)
+ AC_DEFINE(HAVE_OCILOBISTEMPORARY,1,[ ])
+ ], [], [
+ -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
+ ])
+ ], [
+ -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
+ ])
+
+ dnl
+ dnl Check if we have collections
+ dnl
+ PHP_CHECK_LIBRARY(clntsh, OCICollAssign,
+ [
+ AC_DEFINE(HAVE_OCICOLLASSIGN,1,[ ])
+ ], [], [
+ -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
+ ])
+
+ dnl Scrollable cursors?
+ PHP_CHECK_LIBRARY(clntsh, OCIStmtFetch2,
+ [
+ AC_DEFINE(HAVE_OCISTMTFETCH2,1,[ ])
+ ], [], [
+ -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
+ ])
+
+ ifdef([PHP_CHECK_PDO_INCLUDES],
+ [
+ PHP_CHECK_PDO_INCLUDES
+ ],[
+ AC_MSG_CHECKING([for PDO includes])
+ if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
+ pdo_cv_inc_path=$abs_srcdir/ext
+ elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
+ pdo_cv_inc_path=$abs_srcdir/ext
+ elif test -f $prefix/include/php/ext/pdo/php_pdo_driver.h; then
+ pdo_cv_inc_path=$prefix/include/php/ext
+ else
+ AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
+ fi
+ AC_MSG_RESULT($pdo_cv_inc_path)
+ ])
+
+ PHP_NEW_EXTENSION(pdo_oci, pdo_oci.c oci_driver.c oci_statement.c, $ext_shared,,-I$pdo_cv_inc_path)
+
+ PHP_SUBST_OLD(PDO_OCI_SHARED_LIBADD)
+ PHP_SUBST_OLD(PDO_OCI_DIR)
+ PHP_SUBST_OLD(PDO_OCI_VERSION)
+
+ ifdef([PHP_ADD_EXTENSION_DEP],
+ [
+ PHP_ADD_EXTENSION_DEP(pdo_oci, pdo)
+ ])
+
+ AC_DEFINE_UNQUOTED(PHP_PDO_OCI_CLIENT_VERSION, "$PDO_OCI_VERSION", [ ])
+fi
+
diff --git a/ext/pdo_oci/config.w32 b/ext/pdo_oci/config.w32
new file mode 100755
index 0000000..0edf885
--- /dev/null
+++ b/ext/pdo_oci/config.w32
@@ -0,0 +1,46 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_WITH("pdo-oci", "Oracle OCI support for PDO", "no");
+
+if (PHP_PDO_OCI != "no") {
+
+ pdo_oci_dirs = new Array(
+ PHP_PDO_OCI,
+ PHP_PDO_OCI + "\\oci",
+ PHP_PHP_BUILD + "\\instantclient10_*\\sdk",
+ PHP_PHP_BUILD + "\\oci92"
+ );
+
+ pdo_oci_lib_paths = "";
+ pdo_oci_inc_paths = "";
+
+ // find the oracle install
+ for (i = 0; i < pdo_oci_dirs.length; i++) {
+ pdo_oci_lib_paths += pdo_oci_dirs[i] + "\\lib;";
+ pdo_oci_lib_paths += pdo_oci_dirs[i] + "\\lib\\msvc;";
+ pdo_oci_inc_paths += pdo_oci_dirs[i] + "\\include;";
+ }
+
+ pdo_oci_inc_paths += PHP_PHP_BUILD + "\\include\\instantclient;"
+ pdo_oci_lib_paths += PHP_PHP_BUILD + "\\lib\\instantclient;";
+
+ pdo_oci_header = CHECK_HEADER_ADD_INCLUDE("oci.h", "CFLAGS_PDO_OCI", pdo_oci_inc_paths, null, null, true);
+
+ if (pdo_oci_header && CHECK_LIB("oci.lib", "pdo_oci", pdo_oci_lib_paths)) {
+
+ pdo_oci_inc_dir = FSO.GetParentFolderName(pdo_oci_header);
+
+ EXTENSION('pdo_oci', 'pdo_oci.c oci_driver.c oci_statement.c');
+
+ /* probe for some functions not present in older versions */
+ pdo_oci_inc_dir = FSO.GetFolder(pdo_oci_header);
+ CHECK_FUNC_IN_HEADER('oci.h', 'OCIEnvCreate', pdo_oci_inc_dir, 'CFLAGS_PDO_OCI');
+ CHECK_FUNC_IN_HEADER('ociap.h', 'OCIStmtFetch2', pdo_oci_inc_dir, 'CFLAGS_PDO_OCI');
+ CHECK_FUNC_IN_HEADER('ociap.h', 'OCIEnvNlsCreate', pdo_oci_inc_dir, 'CFLAGS_PDO_OCI');
+
+ } else {
+ WARNING("pdo-oci not enabled; libraries and headers not found");
+ }
+ ADD_EXTENSION_DEP('pdo_oci', 'pdo');
+}
diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c
new file mode 100644
index 0000000..5497beb
--- /dev/null
+++ b/ext/pdo_oci/oci_driver.c
@@ -0,0 +1,740 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $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_oci.h"
+#include "php_pdo_oci_int.h"
+#include "Zend/zend_exceptions.h"
+
+static inline ub4 pdo_oci_sanitize_prefetch(long prefetch);
+
+static int pdo_oci_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+ pdo_oci_error_info *einfo;
+
+ einfo = &H->einfo;
+
+ if (stmt) {
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+
+ if (S->einfo.errmsg) {
+ einfo = &S->einfo;
+ }
+ }
+
+ if (einfo->errcode) {
+ add_next_index_long(info, einfo->errcode);
+ add_next_index_string(info, einfo->errmsg, 1);
+ }
+
+ return 1;
+}
+/* }}} */
+
+ub4 _oci_error(OCIError *err, pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *what, sword status, int isinit, const char *file, int line TSRMLS_DC) /* {{{ */
+{
+ text errbuf[1024] = "<<Unknown>>";
+ char tmp_buf[2048];
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+ pdo_oci_error_info *einfo;
+ pdo_oci_stmt *S = NULL;
+ pdo_error_type *pdo_err = &dbh->error_code;
+
+ if (stmt) {
+ S = (pdo_oci_stmt*)stmt->driver_data;
+ einfo = &S->einfo;
+ pdo_err = &stmt->error_code;
+ }
+ else {
+ einfo = &H->einfo;
+ }
+
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ }
+
+ einfo->errmsg = NULL;
+ einfo->errcode = 0;
+ einfo->file = file;
+ einfo->line = line;
+
+ if (isinit) { /* Initialization error */
+ strcpy(*pdo_err, "HY000");
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s (%s:%d)", what, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ }
+ else {
+ switch (status) {
+ case OCI_SUCCESS:
+ strcpy(*pdo_err, "00000");
+ break;
+ case OCI_ERROR:
+ OCIErrorGet(err, (ub4)1, NULL, &einfo->errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: %s (%s:%d)", what, errbuf, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ case OCI_SUCCESS_WITH_INFO:
+ OCIErrorGet(err, (ub4)1, NULL, &einfo->errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_SUCCESS_WITH_INFO: %s (%s:%d)", what, errbuf, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ case OCI_NEED_DATA:
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_NEED_DATA (%s:%d)", what, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ case OCI_NO_DATA:
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_NO_DATA (%s:%d)", what, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ case OCI_INVALID_HANDLE:
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_INVALID_HANDLE (%s:%d)", what, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ case OCI_STILL_EXECUTING:
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_STILL_EXECUTING (%s:%d)", what, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ case OCI_CONTINUE:
+ slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_CONTINUE (%s:%d)", what, file, line);
+ einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
+ break;
+ }
+
+ if (einfo->errcode) {
+ switch (einfo->errcode) {
+ case 1013: /* user requested cancel of current operation */
+ zend_bailout();
+ break;
+
+#if 0
+ case 955: /* ORA-00955: name is already used by an existing object */
+ *pdo_err = PDO_ERR_ALREADY_EXISTS;
+ break;
+#endif
+
+ case 12154: /* ORA-12154: TNS:could not resolve service name */
+ strcpy(*pdo_err, "42S02");
+ break;
+
+ case 22: /* ORA-00022: invalid session id */
+ case 378:
+ case 602:
+ case 603:
+ case 604:
+ case 609:
+ case 1012: /* ORA-01012: */
+ case 1033:
+ case 1041:
+ case 1043:
+ case 1089:
+ case 1090:
+ case 1092:
+ case 3113: /* ORA-03133: end of file on communication channel */
+ case 3114:
+ case 3122:
+ case 3135:
+ case 12153:
+ case 27146:
+ case 28511:
+ /* consider the connection closed */
+ dbh->is_closed = 1;
+ H->attached = 0;
+ strcpy(*pdo_err, "01002"); /* FIXME */
+ break;
+
+ default:
+ strcpy(*pdo_err, "HY000");
+ }
+ }
+
+ if (stmt) {
+ /* always propogate the error code back up to the dbh,
+ * so that we can catch the error information when execute
+ * is called via query. See Bug #33707 */
+ if (H->einfo.errmsg) {
+ pefree(H->einfo.errmsg, dbh->is_persistent);
+ }
+ H->einfo = *einfo;
+ H->einfo.errmsg = einfo->errmsg ? pestrdup(einfo->errmsg, dbh->is_persistent) : NULL;
+ strcpy(dbh->error_code, stmt->error_code);
+ }
+ }
+
+ /* little mini hack so that we can use this code from the dbh ctor */
+ if (!dbh->methods) {
+ zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s]: %s", *pdo_err, einfo->errmsg);
+ }
+
+ return einfo->errcode;
+}
+/* }}} */
+
+static int oci_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+
+ if (H->svc) {
+ /* rollback any outstanding work */
+ OCITransRollback(H->svc, H->err, 0);
+ }
+
+ if (H->session) {
+ OCIHandleFree(H->session, OCI_HTYPE_SESSION);
+ H->session = NULL;
+ }
+
+ if (H->svc) {
+ OCIHandleFree(H->svc, OCI_HTYPE_SVCCTX);
+ H->svc = NULL;
+ }
+
+ if (H->server && H->attached) {
+ H->last_err = OCIServerDetach(H->server, H->err, OCI_DEFAULT);
+ if (H->last_err) {
+ oci_drv_error("OCIServerDetach");
+ }
+ H->attached = 0;
+ }
+
+ if (H->server) {
+ OCIHandleFree(H->server, OCI_HTYPE_SERVER);
+ H->server = NULL;
+ }
+
+ if (H->err) {
+ OCIHandleFree(H->err, OCI_HTYPE_ERROR);
+ H->err = NULL;
+ }
+
+ if (H->charset && H->env) {
+ OCIHandleFree(H->env, OCI_HTYPE_ENV);
+ H->env = NULL;
+ }
+
+ if (H->einfo.errmsg) {
+ pefree(H->einfo.errmsg, dbh->is_persistent);
+ H->einfo.errmsg = NULL;
+ }
+
+ pefree(H, dbh->is_persistent);
+
+ return 0;
+}
+/* }}} */
+
+static int oci_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+ pdo_oci_stmt *S = ecalloc(1, sizeof(*S));
+ ub4 prefetch;
+ char *nsql = NULL;
+ int nsql_len = 0;
+ int ret;
+
+#if HAVE_OCISTMTFETCH2
+ S->exec_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
+ PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL ?
+ OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
+#else
+ S->exec_type = OCI_DEFAULT;
+#endif
+
+ S->H = H;
+ stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
+ ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
+
+ if (ret == 1) {
+ /* query was re-written */
+ sql = nsql;
+ sql_len = nsql_len;
+ } else if (ret == -1) {
+ /* couldn't grok it */
+ strcpy(dbh->error_code, stmt->error_code);
+ efree(S);
+ return 0;
+ }
+
+ /* create an OCI statement handle */
+ OCIHandleAlloc(H->env, (dvoid*)&S->stmt, OCI_HTYPE_STMT, 0, NULL);
+
+ /* and our own private error handle */
+ OCIHandleAlloc(H->env, (dvoid*)&S->err, OCI_HTYPE_ERROR, 0, NULL);
+
+ if (sql_len) {
+ H->last_err = OCIStmtPrepare(S->stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
+ if (nsql) {
+ efree(nsql);
+ nsql = NULL;
+ }
+ if (H->last_err) {
+ H->last_err = oci_drv_error("OCIStmtPrepare");
+ OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
+ OCIHandleFree(S->err, OCI_HTYPE_ERROR);
+ efree(S);
+ return 0;
+ }
+
+ }
+
+ prefetch = pdo_oci_sanitize_prefetch(pdo_attr_lval(driver_options, PDO_ATTR_PREFETCH, PDO_OCI_PREFETCH_DEFAULT TSRMLS_CC));
+ if (prefetch) {
+ H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
+ OCI_ATTR_PREFETCH_ROWS, H->err);
+ if (!H->last_err) {
+ prefetch *= PDO_OCI_PREFETCH_ROWSIZE;
+ H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
+ OCI_ATTR_PREFETCH_MEMORY, H->err);
+ }
+ }
+
+ stmt->driver_data = S;
+ stmt->methods = &oci_stmt_methods;
+ if (nsql) {
+ efree(nsql);
+ nsql = NULL;
+ }
+
+ return 1;
+}
+/* }}} */
+
+static long oci_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+ OCIStmt *stmt;
+ ub2 stmt_type;
+ ub4 rowcount;
+ int ret = -1;
+
+ OCIHandleAlloc(H->env, (dvoid*)&stmt, OCI_HTYPE_STMT, 0, NULL);
+
+ H->last_err = OCIStmtPrepare(stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
+ if (H->last_err) {
+ H->last_err = oci_drv_error("OCIStmtPrepare");
+ OCIHandleFree(stmt, OCI_HTYPE_STMT);
+ return -1;
+ }
+
+ H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &stmt_type, 0, OCI_ATTR_STMT_TYPE, H->err);
+
+ if (stmt_type == OCI_STMT_SELECT) {
+ /* invalid usage; cancel it */
+ OCIHandleFree(stmt, OCI_HTYPE_STMT);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "issuing a SELECT query here is invalid");
+ return -1;
+ }
+
+ /* now we are good to go */
+ H->last_err = OCIStmtExecute(H->svc, stmt, H->err, 1, 0, NULL, NULL,
+ (dbh->auto_commit && !dbh->in_txn) ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
+
+ if (H->last_err) {
+ H->last_err = oci_drv_error("OCIStmtExecute");
+ } else {
+ /* return the number of affected rows */
+ H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, H->err);
+ ret = rowcount;
+ }
+
+ OCIHandleFree(stmt, OCI_HTYPE_STMT);
+
+ return ret;
+}
+/* }}} */
+
+static int oci_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC) /* {{{ */
+{
+ int qcount = 0;
+ char const *cu, *l, *r;
+ char *c;
+
+ if (!unquotedlen) {
+ *quotedlen = 2;
+ *quoted = emalloc(*quotedlen+1);
+ strcpy(*quoted, "''");
+ return 1;
+ }
+
+ /* count single quotes */
+ for (cu = unquoted; (cu = strchr(cu,'\'')); qcount++, cu++)
+ ; /* empty loop */
+
+ *quotedlen = unquotedlen + qcount + 2;
+ *quoted = c = emalloc(*quotedlen+1);
+ *c++ = '\'';
+
+ /* foreach (chunk that ends in a quote) */
+ for (l = unquoted; (r = strchr(l,'\'')); l = r+1) {
+ strncpy(c, l, r-l+1);
+ c += (r-l+1);
+ *c++ = '\''; /* add second quote */
+ }
+
+ /* Copy remainder and add enclosing quote */
+ strncpy(c, l, *quotedlen-(c-*quoted)-1);
+ (*quoted)[*quotedlen-1] = '\'';
+ (*quoted)[*quotedlen] = '\0';
+
+ return 1;
+}
+/* }}} */
+
+static int oci_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ /* with Oracle, there is nothing special to be done */
+ return 1;
+}
+/* }}} */
+
+static int oci_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+
+ H->last_err = OCITransCommit(H->svc, H->err, 0);
+
+ if (H->last_err) {
+ H->last_err = oci_drv_error("OCITransCommit");
+ return 0;
+ }
+ return 1;
+}
+/* }}} */
+
+static int oci_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+
+ H->last_err = OCITransRollback(H->svc, H->err, 0);
+
+ if (H->last_err) {
+ H->last_err = oci_drv_error("OCITransRollback");
+ return 0;
+ }
+ return 1;
+}
+/* }}} */
+
+static int oci_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+
+ if (attr == PDO_ATTR_AUTOCOMMIT) {
+ if (dbh->in_txn) {
+ /* Assume they want to commit whatever is outstanding */
+ H->last_err = OCITransCommit(H->svc, H->err, 0);
+
+ if (H->last_err) {
+ H->last_err = oci_drv_error("OCITransCommit");
+ return 0;
+ }
+ dbh->in_txn = 0;
+ }
+
+ convert_to_long(val);
+
+ dbh->auto_commit = Z_LVAL_P(val);
+ return 1;
+ } else {
+ return 0;
+ }
+
+}
+/* }}} */
+
+static int oci_handle_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+
+ switch (attr) {
+ case PDO_ATTR_SERVER_VERSION:
+ case PDO_ATTR_SERVER_INFO:
+ {
+ text infostr[512];
+ char verstr[15];
+ ub4 vernum;
+
+ if (OCIServerRelease(H->svc, H->err, infostr, (ub4)sizeof(infostr), (ub1)OCI_HTYPE_SVCCTX, &vernum))
+ {
+ ZVAL_STRING(return_value, "<<Unknown>>", 1);
+ } else {
+ if (attr == PDO_ATTR_SERVER_INFO) {
+ ZVAL_STRING(return_value, (char *)infostr, 1);
+ } else {
+ slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d",
+ (int)((vernum>>24) & 0xFF), /* version number */
+ (int)((vernum>>20) & 0x0F), /* release number*/
+ (int)((vernum>>12) & 0xFF), /* update number */
+ (int)((vernum>>8) & 0x0F), /* port release number */
+ (int)((vernum>>0) & 0xFF)); /* port update number */
+
+ ZVAL_STRING(return_value, verstr, 1);
+ }
+ }
+ return TRUE;
+ }
+
+ case PDO_ATTR_CLIENT_VERSION:
+ {
+#if OCI_MAJOR_VERSION > 10 || (OCI_MAJOR_VERSION == 10 && OCI_MINOR_VERSION >= 2)
+ /* Run time client version */
+ sword major, minor, update, patch, port_update;
+ char verstr[15];
+
+ OCIClientVersion(&major, &minor, &update, &patch, &port_update);
+ slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d", major, minor, update, patch, port_update);
+ ZVAL_STRING(return_value, verstr, 1);
+#elif defined(PHP_PDO_OCI_CLIENT_VERSION)
+ /* Compile time client version */
+ ZVAL_STRING(return_value, PHP_PDO_OCI_CLIENT_VERSION, 1);
+#else
+ return FALSE;
+
+#endif /* Check for OCIClientVersion() support */
+
+ return TRUE;
+ }
+
+ case PDO_ATTR_AUTOCOMMIT:
+ ZVAL_BOOL(return_value, dbh->auto_commit);
+ return TRUE;
+
+ default:
+ return FALSE;
+
+ }
+ return FALSE;
+
+}
+/* }}} */
+
+static int pdo_oci_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
+ sb4 error_code = 0;
+ char version[256];
+
+ /* TODO move attached check to PDO level */
+ if (H->attached == 0) {
+ return FAILURE;
+ }
+ /* TODO add persistent_timeout check at PDO level */
+
+
+ /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation)
+ * such as from Pre-10.1 servers, the error is still from the server and we would have
+ * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for
+ * Pre-10.2 clients
+ */
+#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) /* OCIPing available 10.2 onwards */
+ H->last_err = OCIPing (H->svc, H->err, OCI_DEFAULT);
+#else
+ /* use good old OCIServerVersion() */
+ H->last_err = OCIServerVersion (H->svc, H->err, (text *)version, sizeof(version), OCI_HTYPE_SVCCTX);
+#endif
+ if (H->last_err == OCI_SUCCESS) {
+ return SUCCESS;
+ }
+
+ OCIErrorGet (H->err, (ub4)1, NULL, &error_code, NULL, 0, OCI_HTYPE_ERROR);
+
+ if (error_code == 1010) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+static struct pdo_dbh_methods oci_methods = {
+ oci_handle_closer,
+ oci_handle_preparer,
+ oci_handle_doer,
+ oci_handle_quoter,
+ oci_handle_begin,
+ oci_handle_commit,
+ oci_handle_rollback,
+ oci_handle_set_attribute,
+ NULL,
+ pdo_oci_fetch_error_func,
+ oci_handle_get_attribute,
+ pdo_oci_check_liveness, /* check_liveness */
+ NULL /* get_driver_methods */
+};
+
+static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_db_handle *H;
+ int i, ret = 0;
+ struct pdo_data_src_parser vars[] = {
+ { "charset", NULL, 0 },
+ { "dbname", "", 0 }
+ };
+
+ php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 2);
+
+ H = pecalloc(1, sizeof(*H), dbh->is_persistent);
+ dbh->driver_data = H;
+
+ /* allocate an environment */
+#if HAVE_OCIENVNLSCREATE
+ if (vars[0].optval) {
+ H->charset = OCINlsCharSetNameToId(pdo_oci_Env, (const oratext *)vars[0].optval);
+ if (!H->charset) {
+ oci_init_error("OCINlsCharSetNameToId: unknown character set name");
+ goto cleanup;
+ } else {
+ if (OCIEnvNlsCreate(&H->env, PDO_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, H->charset, H->charset) != OCI_SUCCESS) {
+ oci_init_error("OCIEnvNlsCreate: Check the character set is valid and that PHP has access to Oracle libraries and NLS data");
+ goto cleanup;
+ }
+ }
+ }
+#endif
+ if (H->env == NULL) {
+ /* use the global environment */
+ H->env = pdo_oci_Env;
+ }
+
+ /* something to hold errors */
+ OCIHandleAlloc(H->env, (dvoid **)&H->err, OCI_HTYPE_ERROR, 0, NULL);
+
+ /* handle for the server */
+ OCIHandleAlloc(H->env, (dvoid **)&H->server, OCI_HTYPE_SERVER, 0, NULL);
+
+ H->last_err = OCIServerAttach(H->server, H->err, (text*)vars[1].optval,
+ strlen(vars[1].optval), OCI_DEFAULT);
+
+ if (H->last_err) {
+ oci_drv_error("pdo_oci_handle_factory");
+ goto cleanup;
+ }
+
+ H->attached = 1;
+
+ /* create a service context */
+ H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->svc, OCI_HTYPE_SVCCTX, 0, NULL);
+ if (H->last_err) {
+ oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SVCCTX");
+ goto cleanup;
+ }
+
+ H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->session, OCI_HTYPE_SESSION, 0, NULL);
+ if (H->last_err) {
+ oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SESSION");
+ goto cleanup;
+ }
+
+ /* set server handle into service handle */
+ H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->server, 0, OCI_ATTR_SERVER, H->err);
+ if (H->last_err) {
+ oci_drv_error("OCIAttrSet: OCI_ATTR_SERVER");
+ goto cleanup;
+ }
+
+ /* username */
+ if (dbh->username) {
+ H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
+ dbh->username, strlen(dbh->username),
+ OCI_ATTR_USERNAME, H->err);
+ if (H->last_err) {
+ oci_drv_error("OCIAttrSet: OCI_ATTR_USERNAME");
+ goto cleanup;
+ }
+ }
+
+ /* password */
+ if (dbh->password) {
+ H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
+ dbh->password, strlen(dbh->password),
+ OCI_ATTR_PASSWORD, H->err);
+ if (H->last_err) {
+ oci_drv_error("OCIAttrSet: OCI_ATTR_PASSWORD");
+ goto cleanup;
+ }
+ }
+
+ /* Now fire up the session */
+ H->last_err = OCISessionBegin(H->svc, H->err, H->session, OCI_CRED_RDBMS, OCI_DEFAULT);
+ if (H->last_err) {
+ oci_drv_error("OCISessionBegin");
+ goto cleanup;
+ }
+
+ /* set the server handle into service handle */
+ H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->session, 0, OCI_ATTR_SESSION, H->err);
+ if (H->last_err) {
+ oci_drv_error("OCIAttrSet: OCI_ATTR_SESSION");
+ goto cleanup;
+ }
+
+ dbh->methods = &oci_methods;
+ dbh->alloc_own_columns = 1;
+ dbh->native_case = PDO_CASE_UPPER;
+
+ ret = 1;
+
+cleanup:
+ for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
+ if (vars[i].freeme) {
+ efree(vars[i].optval);
+ }
+ }
+
+ if (!ret) {
+ oci_handle_closer(dbh TSRMLS_CC);
+ }
+
+ return ret;
+}
+/* }}} */
+
+pdo_driver_t pdo_oci_driver = {
+ PDO_DRIVER_HEADER(oci),
+ pdo_oci_handle_factory
+};
+
+static inline ub4 pdo_oci_sanitize_prefetch(long prefetch) /* {{{ */
+{
+ if (prefetch < 0) {
+ prefetch = 0;
+ } else if (prefetch > UB4MAXVAL / PDO_OCI_PREFETCH_ROWSIZE) {
+ prefetch = PDO_OCI_PREFETCH_DEFAULT;
+ }
+ return ((ub4)prefetch);
+}
+/* }}} */
+
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_oci/oci_statement.c b/ext/pdo_oci/oci_statement.c
new file mode 100644
index 0000000..dcb9557
--- /dev/null
+++ b/ext/pdo_oci/oci_statement.c
@@ -0,0 +1,767 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $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_oci.h"
+#include "php_pdo_oci_int.h"
+#include "Zend/zend_extensions.h"
+
+#define PDO_OCI_LOBMAXSIZE (4294967295UL) /* OCI_LOBMAXSIZE */
+
+#define STMT_CALL(name, params) \
+ do { \
+ S->last_err = name params; \
+ S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
+ if (S->last_err) { \
+ return 0; \
+ } \
+ } while(0)
+
+#define STMT_CALL_MSG(name, msg, params) \
+ do { \
+ S->last_err = name params; \
+ S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name ": " #msg, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
+ if (S->last_err) { \
+ return 0; \
+ } \
+ } while(0)
+
+static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC);
+
+static int oci_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+ HashTable *BC = stmt->bound_columns;
+ HashTable *BP = stmt->bound_params;
+
+ int i;
+
+ if (S->stmt) {
+ /* cancel server side resources for the statement if we didn't
+ * fetch it all */
+ OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
+
+ /* free the handle */
+ OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
+ S->stmt = NULL;
+ }
+ if (S->err) {
+ OCIHandleFree(S->err, OCI_HTYPE_ERROR);
+ S->err = NULL;
+ }
+
+ /* need to ensure these go away now */
+ if (BC) {
+ zend_hash_destroy(BC);
+ FREE_HASHTABLE(stmt->bound_columns);
+ stmt->bound_columns = NULL;
+ }
+
+ if (BP) {
+ zend_hash_destroy(BP);
+ FREE_HASHTABLE(stmt->bound_params);
+ stmt->bound_params = NULL;
+ }
+
+ if (S->einfo.errmsg) {
+ pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
+ S->einfo.errmsg = NULL;
+ }
+
+ if (S->cols) {
+ for (i = 0; i < stmt->column_count; i++) {
+ if (S->cols[i].data) {
+ switch (S->cols[i].dtype) {
+ case SQLT_BLOB:
+ case SQLT_CLOB:
+ OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
+ break;
+ default:
+ efree(S->cols[i].data);
+ }
+ }
+ }
+ efree(S->cols);
+ S->cols = NULL;
+ }
+ efree(S);
+
+ stmt->driver_data = NULL;
+
+ return 1;
+} /* }}} */
+
+static int oci_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+ ub4 rowcount;
+ b4 mode;
+
+ if (!S->stmt_type) {
+ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_STMT_TYPE",
+ (S->stmt, OCI_HTYPE_STMT, &S->stmt_type, 0, OCI_ATTR_STMT_TYPE, S->err));
+ }
+
+ if (stmt->executed) {
+ /* ensure that we cancel the cursor from a previous fetch */
+ OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
+ }
+
+#ifdef OCI_STMT_SCROLLABLE_READONLY /* needed for oci8 ? */
+ if (S->exec_type == OCI_STMT_SCROLLABLE_READONLY) {
+ mode = OCI_STMT_SCROLLABLE_READONLY;
+ } else
+#endif
+ if (stmt->dbh->auto_commit && !stmt->dbh->in_txn) {
+ mode = OCI_COMMIT_ON_SUCCESS;
+ } else {
+ mode = OCI_DEFAULT;
+ }
+
+ STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err,
+ (S->stmt_type == OCI_STMT_SELECT && !S->have_blobs) ? 0 : 1, 0, NULL, NULL,
+ mode));
+
+ if (!stmt->executed) {
+ ub4 colcount;
+ /* do first-time-only definition of bind/mapping stuff */
+
+ /* how many columns do we have ? */
+ STMT_CALL_MSG(OCIAttrGet, "ATTR_PARAM_COUNT",
+ (S->stmt, OCI_HTYPE_STMT, &colcount, 0, OCI_ATTR_PARAM_COUNT, S->err));
+
+ stmt->column_count = (int)colcount;
+
+ if (S->cols) {
+ int i;
+ for (i = 0; i < stmt->column_count; i++) {
+ if (S->cols[i].data) {
+ switch (S->cols[i].dtype) {
+ case SQLT_BLOB:
+ case SQLT_CLOB:
+ /* do nothing */
+ break;
+ default:
+ efree(S->cols[i].data);
+ }
+ }
+ }
+ efree(S->cols);
+ }
+
+ S->cols = ecalloc(colcount, sizeof(pdo_oci_column));
+ }
+
+ STMT_CALL_MSG(OCIAttrGet, "ATTR_ROW_COUNT",
+ (S->stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, S->err));
+ stmt->row_count = (long)rowcount;
+
+ return 1;
+} /* }}} */
+
+static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep, dvoid **indpp) /* {{{ */
+{
+ struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
+ pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
+ TSRMLS_FETCH();
+
+ if (!param || !param->parameter) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_input_cb; this should not happen");
+ return OCI_ERROR;
+ }
+
+ *indpp = &P->indicator;
+
+ if (P->thing) {
+ *bufpp = P->thing;
+ *alenp = sizeof(void*);
+ } else if (ZVAL_IS_NULL(param->parameter)) {
+ /* insert a NULL value into the column */
+ P->indicator = -1; /* NULL */
+ *bufpp = 0;
+ *alenp = -1;
+ } else if (!P->thing) {
+ /* regular string bind */
+ convert_to_string(param->parameter);
+ *bufpp = Z_STRVAL_P(param->parameter);
+ *alenp = Z_STRLEN_P(param->parameter);
+ }
+
+ *piecep = OCI_ONE_PIECE;
+ return OCI_CONTINUE;
+} /* }}} */
+
+static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) /* {{{ */
+{
+ struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
+ pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
+ TSRMLS_FETCH();
+
+ if (!param || !param->parameter) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_output_cb; this should not happen");
+ return OCI_ERROR;
+ }
+
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
+ P->actual_len = sizeof(OCILobLocator*);
+ *bufpp = P->thing;
+ *alenpp = &P->actual_len;
+ *piecep = OCI_ONE_PIECE;
+ *rcodepp = &P->retcode;
+ *indpp = &P->indicator;
+ return OCI_CONTINUE;
+ }
+
+ if (Z_TYPE_P(param->parameter) == IS_OBJECT || Z_TYPE_P(param->parameter) == IS_RESOURCE) {
+ return OCI_CONTINUE;
+ }
+
+ convert_to_string(param->parameter);
+ zval_dtor(param->parameter);
+
+ Z_STRLEN_P(param->parameter) = param->max_value_len;
+ Z_STRVAL_P(param->parameter) = ecalloc(1, Z_STRLEN_P(param->parameter)+1);
+ P->used_for_output = 1;
+
+ P->actual_len = Z_STRLEN_P(param->parameter);
+ *alenpp = &P->actual_len;
+ *bufpp = Z_STRVAL_P(param->parameter);
+ *piecep = OCI_ONE_PIECE;
+ *rcodepp = &P->retcode;
+ *indpp = &P->indicator;
+
+ return OCI_CONTINUE;
+} /* }}} */
+
+static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+
+ /* we're only interested in parameters for prepared SQL right now */
+ if (param->is_param) {
+ pdo_oci_bound_param *P;
+ sb4 value_sz = -1;
+
+ P = (pdo_oci_bound_param*)param->driver_data;
+
+ switch (event_type) {
+ case PDO_PARAM_EVT_FREE:
+ P = param->driver_data;
+ if (P) {
+ efree(P);
+ }
+ break;
+
+ case PDO_PARAM_EVT_ALLOC:
+ P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
+ param->driver_data = P;
+
+ /* figure out what we're doing */
+ switch (PDO_PARAM_TYPE(param->param_type)) {
+ case PDO_PARAM_STMT:
+ return 0;
+
+ case PDO_PARAM_LOB:
+ /* P->thing is now an OCILobLocator * */
+ P->oci_type = SQLT_BLOB;
+ value_sz = sizeof(OCILobLocator*);
+ break;
+
+ case PDO_PARAM_STR:
+ default:
+ P->oci_type = SQLT_CHR;
+ value_sz = param->max_value_len;
+ if (param->max_value_len == 0) {
+ value_sz = 1332; /* maximum size before value is interpreted as a LONG value */
+ }
+
+ }
+
+ if (param->name) {
+ STMT_CALL(OCIBindByName, (S->stmt,
+ &P->bind, S->err, (text*)param->name,
+ param->namelen, 0, value_sz, P->oci_type,
+ &P->indicator, 0, &P->retcode, 0, 0,
+ OCI_DATA_AT_EXEC));
+ } else {
+ STMT_CALL(OCIBindByPos, (S->stmt,
+ &P->bind, S->err, param->paramno+1,
+ 0, value_sz, P->oci_type,
+ &P->indicator, 0, &P->retcode, 0, 0,
+ OCI_DATA_AT_EXEC));
+ }
+
+ STMT_CALL(OCIBindDynamic, (P->bind,
+ S->err,
+ param, oci_bind_input_cb,
+ param, oci_bind_output_cb));
+
+ return 1;
+
+ case PDO_PARAM_EVT_EXEC_PRE:
+ P->indicator = 0;
+ P->used_for_output = 0;
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
+ ub4 empty = 0;
+ STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
+ STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
+ S->have_blobs = 1;
+ }
+ return 1;
+
+ case PDO_PARAM_EVT_EXEC_POST:
+ /* fixup stuff set in motion in oci_bind_output_cb */
+ if (P->used_for_output) {
+ if (P->indicator == -1) {
+ /* set up a NULL value */
+ if (Z_TYPE_P(param->parameter) == IS_STRING
+#if ZEND_EXTENSION_API_NO < 220040718
+ && Z_STRVAL_P(param->parameter) != empty_string
+#endif
+ ) {
+ /* OCI likes to stick non-terminated strings in things */
+ *Z_STRVAL_P(param->parameter) = '\0';
+ }
+ zval_dtor(param->parameter);
+ ZVAL_NULL(param->parameter);
+ } else if (Z_TYPE_P(param->parameter) == IS_STRING
+#if ZEND_EXTENSION_API_NO < 220040718
+ && Z_STRVAL_P(param->parameter) != empty_string
+#endif
+ ) {
+ Z_STRLEN_P(param->parameter) = P->actual_len;
+ Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->actual_len+1);
+ Z_STRVAL_P(param->parameter)[P->actual_len] = '\0';
+ }
+ } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
+ php_stream *stm;
+
+ if (Z_TYPE_P(param->parameter) == IS_NULL) {
+ /* if the param is NULL, then we assume that they
+ * wanted to bind a lob locator into it from the query
+ * */
+
+ stm = oci_create_lob_stream(stmt, (OCILobLocator*)P->thing TSRMLS_CC);
+ if (stm) {
+ OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
+ php_stream_to_zval(stm, param->parameter);
+ P->thing = NULL;
+ }
+ } else {
+ /* we're a LOB being used for insert; transfer the data now */
+ size_t n;
+ ub4 amt, offset = 1;
+ char *consume;
+
+ php_stream_from_zval_no_verify(stm, &param->parameter);
+ if (stm) {
+ OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
+ do {
+ char buf[8192];
+ n = php_stream_read(stm, buf, sizeof(buf));
+ if ((int)n <= 0) {
+ break;
+ }
+ consume = buf;
+ do {
+ amt = n;
+ OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
+ &amt, offset, consume, n,
+ OCI_ONE_PIECE,
+ NULL, NULL, 0, SQLCS_IMPLICIT);
+ offset += amt;
+ n -= amt;
+ consume += amt;
+ } while (n);
+ } while (1);
+ OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
+ OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
+ } else if (Z_TYPE_P(param->parameter) == IS_STRING) {
+ /* stick the string into the LOB */
+ consume = Z_STRVAL_P(param->parameter);
+ n = Z_STRLEN_P(param->parameter);
+ if (n) {
+ OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
+ while (n) {
+ amt = n;
+ OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
+ &amt, offset, consume, n,
+ OCI_ONE_PIECE,
+ NULL, NULL, 0, SQLCS_IMPLICIT);
+ consume += amt;
+ n -= amt;
+ }
+ OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
+ }
+ }
+ OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
+ P->thing = NULL;
+ }
+ }
+
+ return 1;
+ }
+ }
+
+ return 1;
+} /* }}} */
+
+static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC) /* {{{ */
+{
+#if HAVE_OCISTMTFETCH2
+ ub4 ociori;
+#endif
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+
+#if HAVE_OCISTMTFETCH2
+ switch (ori) {
+ case PDO_FETCH_ORI_NEXT: ociori = OCI_FETCH_NEXT; break;
+ case PDO_FETCH_ORI_PRIOR: ociori = OCI_FETCH_PRIOR; break;
+ case PDO_FETCH_ORI_FIRST: ociori = OCI_FETCH_FIRST; break;
+ case PDO_FETCH_ORI_LAST: ociori = OCI_FETCH_LAST; break;
+ case PDO_FETCH_ORI_ABS: ociori = OCI_FETCH_ABSOLUTE; break;
+ case PDO_FETCH_ORI_REL: ociori = OCI_FETCH_RELATIVE; break;
+ }
+ S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, offset, OCI_DEFAULT);
+#else
+ S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
+#endif
+
+ if (S->last_err == OCI_NO_DATA) {
+ /* no (more) data */
+ return 0;
+ }
+
+ if (S->last_err == OCI_NEED_DATA) {
+ oci_stmt_error("OCI_NEED_DATA");
+ return 0;
+ }
+
+ if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
+ return 1;
+ }
+
+ oci_stmt_error("OCIStmtFetch");
+
+ return 0;
+} /* }}} */
+
+static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
+ ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
+{
+ pdo_oci_column *col = (pdo_oci_column*)octxp;
+ TSRMLS_FETCH();
+
+ switch (col->dtype) {
+ case SQLT_BLOB:
+ case SQLT_CLOB:
+ *piecep = OCI_ONE_PIECE;
+ *bufpp = col->data;
+ *alenpp = &col->datalen;
+ *indpp = (dvoid *)&col->indicator;
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "unhandled datatype in oci_define_callback; this should not happen");
+ return OCI_ERROR;
+ }
+
+ return OCI_CONTINUE;
+}
+
+static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+ OCIParam *param = NULL;
+ text *colname;
+ ub2 dtype, data_size, scale, precis;
+ ub4 namelen;
+ struct pdo_column_data *col = &stmt->columns[colno];
+ zend_bool dyn = FALSE;
+
+ /* describe the column */
+ STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)&param, colno+1));
+
+ /* what type ? */
+ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
+ (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
+
+ /* how big ? */
+ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
+ (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
+
+ /* scale ? */
+ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
+ (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
+
+ /* precision ? */
+ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
+ (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
+
+ /* name ? */
+ STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
+ (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
+
+ col->precision = scale;
+ col->maxlen = data_size;
+ col->namelen = namelen;
+ col->name = estrndup((char *)colname, namelen);
+
+ S->cols[colno].dtype = dtype;
+
+ /* how much room do we need to store the field */
+ switch (dtype) {
+ case SQLT_LBI:
+ case SQLT_LNG:
+ if (dtype == SQLT_LBI) {
+ dtype = SQLT_BIN;
+ } else {
+ dtype = SQLT_CHR;
+ }
+ S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
+ S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
+ col->param_type = PDO_PARAM_STR;
+ break;
+
+ case SQLT_BLOB:
+ case SQLT_CLOB:
+ col->param_type = PDO_PARAM_LOB;
+ STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
+ S->cols[colno].datalen = sizeof(OCILobLocator*);
+ dyn = TRUE;
+ break;
+
+ case SQLT_BIN:
+ default:
+ if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
+#ifdef SQLT_TIMESTAMP
+ || dtype == SQLT_TIMESTAMP
+#endif
+#ifdef SQLT_TIMESTAMP_TZ
+ || dtype == SQLT_TIMESTAMP_TZ
+#endif
+ ) {
+ /* should be big enough for most date formats and numbers */
+ S->cols[colno].datalen = 512;
+#if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
+ } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
+ S->cols[colno].datalen = 1024;
+#endif
+ } else {
+ S->cols[colno].datalen = col->maxlen;
+ }
+ if (dtype == SQLT_BIN) {
+ S->cols[colno].datalen *= 3;
+ }
+ S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
+ dtype = SQLT_CHR;
+
+ /* returning data as a string */
+ col->param_type = PDO_PARAM_STR;
+ }
+
+ STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
+ S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
+ &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
+
+ if (dyn) {
+ STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
+ oci_define_callback));
+ }
+
+ return 1;
+} /* }}} */
+
+struct oci_lob_self {
+ pdo_stmt_t *stmt;
+ pdo_oci_stmt *S;
+ OCILobLocator *lob;
+ ub4 offset;
+};
+
+static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
+ ub4 amt;
+ sword r;
+
+ amt = count;
+ r = OCILobWrite(self->S->H->svc, self->S->err, self->lob,
+ &amt, self->offset, (char*)buf, count,
+ OCI_ONE_PIECE,
+ NULL, NULL, 0, SQLCS_IMPLICIT);
+
+ if (r != OCI_SUCCESS) {
+ return (size_t)-1;
+ }
+
+ self->offset += amt;
+ return amt;
+}
+
+static size_t oci_blob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
+ ub4 amt;
+ sword r;
+
+ amt = count;
+ r = OCILobRead(self->S->H->svc, self->S->err, self->lob,
+ &amt, self->offset, buf, count,
+ NULL, NULL, 0, SQLCS_IMPLICIT);
+
+ if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
+ return (size_t)-1;
+ }
+
+ self->offset += amt;
+ if (amt < count) {
+ stream->eof = 1;
+ }
+ return amt;
+}
+
+static int oci_blob_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
+ pdo_stmt_t *stmt = self->stmt;
+
+ if (close_handle) {
+ OCILobClose(self->S->H->svc, self->S->err, self->lob);
+ efree(self);
+ }
+
+ php_pdo_stmt_delref(stmt TSRMLS_CC);
+ return 0;
+}
+
+static int oci_blob_flush(php_stream *stream TSRMLS_DC)
+{
+ struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
+ OCILobFlushBuffer(self->S->H->svc, self->S->err, self->lob, 0);
+ return 0;
+}
+
+static int oci_blob_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
+{
+ struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
+
+ if (offset >= PDO_OCI_LOBMAXSIZE) {
+ return -1;
+ } else {
+ self->offset = offset + 1; /* Oracle LOBS are 1-based, but PHP is 0-based */
+ return 0;
+ }
+}
+
+static php_stream_ops oci_blob_stream_ops = {
+ oci_blob_write,
+ oci_blob_read,
+ oci_blob_close,
+ oci_blob_flush,
+ "pdo_oci blob stream",
+ oci_blob_seek,
+ NULL,
+ NULL,
+ NULL
+};
+
+static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC)
+{
+ php_stream *stm;
+ struct oci_lob_self *self = ecalloc(1, sizeof(*self));
+ self->lob = lob;
+ self->offset = 1; /* 1-based */
+ self->stmt = stmt;
+ self->S = (pdo_oci_stmt*)stmt->driver_data;
+
+ stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
+
+ if (stm) {
+ php_pdo_stmt_addref(stmt TSRMLS_CC);
+ return stm;
+ }
+
+ efree(self);
+ return NULL;
+}
+
+static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */
+{
+ pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
+ pdo_oci_column *C = &S->cols[colno];
+
+ /* check the indicator to ensure that the data is intact */
+ if (C->indicator == -1) {
+ /* A NULL value */
+ *ptr = NULL;
+ *len = 0;
+ return 1;
+ } else if (C->indicator == 0) {
+ /* it was stored perfectly */
+
+ if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
+ if (C->data) {
+ *ptr = (char*)oci_create_lob_stream(stmt, (OCILobLocator*)C->data TSRMLS_CC);
+ OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
+ }
+ *len = 0;
+ return *ptr ? 1 : 0;
+ }
+
+ *ptr = C->data;
+ *len = C->fetched_len;
+ return 1;
+ } else {
+ /* it was truncated */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d data was too large for buffer and was truncated to fit it", colno);
+
+ *ptr = C->data;
+ *len = C->fetched_len;
+ return 1;
+ }
+} /* }}} */
+
+struct pdo_stmt_methods oci_stmt_methods = {
+ oci_stmt_dtor,
+ oci_stmt_execute,
+ oci_stmt_fetch,
+ oci_stmt_describe,
+ oci_stmt_get_col,
+ oci_stmt_param_hook
+};
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_oci/package2.xml b/ext/pdo_oci/package2.xml
new file mode 100644
index 0000000..1f828d1
--- /dev/null
+++ b/ext/pdo_oci/package2.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>PDO_OCI</name>
+ <channel>pecl.php.net</channel>
+ <summary>Oracle Call Interface driver for PDO</summary>
+ <description>This extension provides an Oracle driver for PDO.
+ </description>
+ <lead>
+ <name>Wez Furlong</name>
+ <user>wez</user>
+ <email>wez@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2006-05-01</date>
+ <version>
+ <release>1.0.1</release>
+ <api>1.0.1</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>
+- Added support for BINARY_DOUBLE and BINARY_FLOAT to PDO_OCI and OCI8
+ (also fixes bug #36764). (Tony)
+- Fixed bug #35907 (PDO_OCI uses hardcoded lib path $ORACLE_HOME/lib). (Tony)
+- Repackage with package2.xml
+- Improved handling of long columns
+- Fixed PECL Bug #5722; implemented LOB support.
+
+You require Oracle OCI 8 or higher client libraries (instantclient is also
+supported) installed on the machine where you intend to build and/or use this
+package.
+
+If you are running on windows, you can download the binary from here:
+http://pecl4win.php.net/ext.php/php_pdo_oci.dll
+ </notes>
+ <contents>
+ <dir name="/">
+ <file name="config.m4" role="src" />
+ <file name="config.w32" role="src" />
+ <file name="CREDITS" role="doc" />
+ <file name="oci_driver.c" role="src" />
+ <file name="oci_statement.c" role="src" />
+ <file name="pdo_oci.c" role="src" />
+ <file name="php_pdo_oci.h" role="src" />
+ <file name="php_pdo_oci_int.h" role="src" />
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.0.3</min>
+ </php>
+ <pearinstaller>
+ <min>1.4.0</min>
+ </pearinstaller>
+ <package>
+ <name>pdo</name>
+ <channel>pecl.php.net</channel>
+ <min>1.0.3</min>
+ <providesextension>PDO</providesextension>
+ </package>
+ </required>
+ </dependencies>
+ <providesextension>PDO_OCI</providesextension>
+ <extsrcrelease />
+</package>
diff --git a/ext/pdo_oci/pdo_oci.c b/ext/pdo_oci/pdo_oci.c
new file mode 100644
index 0000000..6957714
--- /dev/null
+++ b/ext/pdo_oci/pdo_oci.c
@@ -0,0 +1,133 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $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_oci.h"
+#include "php_pdo_oci_int.h"
+
+/* {{{ pdo_oci_functions[] */
+const zend_function_entry pdo_oci_functions[] = {
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ pdo_oci_module_entry */
+
+#if ZEND_MODULE_API_NO >= 20050922
+static const zend_module_dep pdo_oci_deps[] = {
+ ZEND_MOD_REQUIRED("pdo")
+ ZEND_MOD_END
+};
+#endif
+
+zend_module_entry pdo_oci_module_entry = {
+#if ZEND_MODULE_API_NO >= 20050922
+ STANDARD_MODULE_HEADER_EX, NULL,
+ pdo_oci_deps,
+#else
+ STANDARD_MODULE_HEADER,
+#endif
+ "PDO_OCI",
+ pdo_oci_functions,
+ PHP_MINIT(pdo_oci),
+ PHP_MSHUTDOWN(pdo_oci),
+ NULL,
+ NULL,
+ PHP_MINFO(pdo_oci),
+ "1.0.1",
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_PDO_OCI
+ZEND_GET_MODULE(pdo_oci)
+#endif
+
+const ub4 PDO_OCI_INIT_MODE =
+#if 0 && defined(OCI_SHARED)
+ /* shared mode is known to be bad for PHP */
+ OCI_SHARED
+#else
+ OCI_DEFAULT
+#endif
+#ifdef OCI_OBJECT
+ |OCI_OBJECT
+#endif
+#ifdef ZTS
+ |OCI_THREADED
+#endif
+ ;
+
+/* true global environment */
+OCIEnv *pdo_oci_Env = NULL;
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(pdo_oci)
+{
+ php_pdo_register_driver(&pdo_oci_driver);
+
+#if HAVE_OCIENVCREATE
+ OCIEnvCreate(&pdo_oci_Env, PDO_OCI_INIT_MODE, NULL, NULL, NULL, NULL, 0, NULL);
+#else
+ OCIInitialize(PDO_OCI_INIT_MODE, NULL, NULL, NULL, NULL);
+ OCIEnvInit(&pdo_oci_Env, OCI_DEFAULT, 0, NULL);
+#endif
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(pdo_oci)
+{
+ php_pdo_unregister_driver(&pdo_oci_driver);
+ OCIHandleFree((dvoid*)pdo_oci_Env, OCI_HTYPE_ENV);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(pdo_oci)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "PDO Driver for OCI 8 and later", "enabled");
+ php_info_print_table_end();
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_oci/php_pdo_oci.h b/ext/pdo_oci/php_pdo_oci.h
new file mode 100644
index 0000000..d0b1b3d
--- /dev/null
+++ b/ext/pdo_oci/php_pdo_oci.h
@@ -0,0 +1,47 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_OCI_H
+#define PHP_PDO_OCI_H
+
+extern zend_module_entry pdo_oci_module_entry;
+#define phpext_pdo_oci_ptr &pdo_oci_module_entry
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+PHP_MINIT_FUNCTION(pdo_oci);
+PHP_MSHUTDOWN_FUNCTION(pdo_oci);
+PHP_RINIT_FUNCTION(pdo_oci);
+PHP_RSHUTDOWN_FUNCTION(pdo_oci);
+PHP_MINFO_FUNCTION(pdo_oci);
+
+#endif /* PHP_PDO_OCI_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
+ */
diff --git a/ext/pdo_oci/php_pdo_oci_int.h b/ext/pdo_oci/php_pdo_oci_int.h
new file mode 100644
index 0000000..af5618b
--- /dev/null
+++ b/ext/pdo_oci/php_pdo_oci_int.h
@@ -0,0 +1,100 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include <oci.h>
+
+typedef struct {
+ const char *file;
+ int line;
+ sb4 errcode;
+ char *errmsg;
+} pdo_oci_error_info;
+
+/* stuff we use in an OCI database handle */
+typedef struct {
+ OCIServer *server;
+ OCISession *session;
+ OCIEnv *env;
+ OCIError *err;
+ OCISvcCtx *svc;
+ /* OCI9; 0 == use NLS_LANG */
+ ub2 charset;
+ sword last_err;
+
+ unsigned attached:1;
+ unsigned _reserved:31;
+
+ pdo_oci_error_info einfo;
+} pdo_oci_db_handle;
+
+typedef struct {
+ OCIDefine *def;
+ ub2 fetched_len;
+ ub2 retcode;
+ sb2 indicator;
+
+ char *data;
+ ub4 datalen;
+
+ ub2 dtype;
+
+} pdo_oci_column;
+
+typedef struct {
+ pdo_oci_db_handle *H;
+ OCIStmt *stmt;
+ OCIError *err;
+ sword last_err;
+ ub2 stmt_type;
+ ub4 exec_type;
+ pdo_oci_column *cols;
+ pdo_oci_error_info einfo;
+ unsigned int have_blobs:1;
+} pdo_oci_stmt;
+
+typedef struct {
+ OCIBind *bind; /* allocated by OCI */
+ sb2 oci_type;
+ sb2 indicator;
+ ub2 retcode;
+
+ ub4 actual_len;
+
+ dvoid *thing; /* for LOBS, REFCURSORS etc. */
+
+ unsigned used_for_output;
+} pdo_oci_bound_param;
+
+extern const ub4 PDO_OCI_INIT_MODE;
+extern pdo_driver_t pdo_oci_driver;
+extern OCIEnv *pdo_oci_Env;
+
+ub4 _oci_error(OCIError *err, pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *what, sword status, int isinit, const char *file, int line TSRMLS_DC);
+#define oci_init_error(w) _oci_error(H->err, dbh, NULL, w, H->last_err, TRUE, __FILE__, __LINE__ TSRMLS_CC)
+#define oci_drv_error(w) _oci_error(H->err, dbh, NULL, w, H->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC)
+#define oci_stmt_error(w) _oci_error(S->err, stmt->dbh, stmt, w, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC)
+
+extern struct pdo_stmt_methods oci_stmt_methods;
+
+/* Default prefetch size in number of rows */
+#define PDO_OCI_PREFETCH_DEFAULT 100
+
+/* Arbitrary assumed row length for prefetch memory limit calcuation */
+#define PDO_OCI_PREFETCH_ROWSIZE 1024
diff --git a/ext/pdo_oci/tests/bug41996.phpt b/ext/pdo_oci/tests/bug41996.phpt
new file mode 100644
index 0000000..ac8e35f
--- /dev/null
+++ b/ext/pdo_oci/tests/bug41996.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PDO OCI Bug #41996 (Problem accessing Oracle ROWID)
+--SKIPIF--
+<?php
+/* $Id$ */
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require dirname(__FILE__).'/../../pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require 'ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
+
+$stmt = $db->prepare('SELECT rowid FROM dual');
+$stmt->execute();
+$row = $stmt->fetch();
+var_dump(strlen($row[0]) > 0);
+--EXPECTF--
+bool(true)
diff --git a/ext/pdo_oci/tests/bug44301.phpt b/ext/pdo_oci/tests/bug44301.phpt
new file mode 100644
index 0000000..c0f7935
--- /dev/null
+++ b/ext/pdo_oci/tests/bug44301.phpt
@@ -0,0 +1,25 @@
+--TEST--
+PDO OCI Bug #44301 (Segfault when an exception is thrown on persistent connections)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require dirname(__FILE__).'/../../pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+putenv("PDO_OCI_TEST_ATTR=" . serialize(array(PDO::ATTR_PERSISTENT => true)));
+require 'ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+try {
+ $stmt = $db->prepare('SELECT * FROM no_table');
+ $stmt->execute();
+} catch (PDOException $e) {
+ print $e->getMessage();
+}
+$db = null;
+--EXPECTF--
+SQLSTATE[HY000]: General error: 942 OCIStmtExecute: ORA-00942: table or view does not exist
+ (%s/ext/pdo_oci/oci_statement.c:%d)
diff --git a/ext/pdo_oci/tests/bug46274.phpt b/ext/pdo_oci/tests/bug46274.phpt
new file mode 100644
index 0000000..77f2a01
--- /dev/null
+++ b/ext/pdo_oci/tests/bug46274.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Bug #46274 (pdo_pgsql - Segfault when using PDO::ATTR_STRINGIFY_FETCHES and blob)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci'))
+die('skip not loaded');
+require dirname(__FILE__).'/../../pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require 'ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
+
+try {
+ $db->exec("DROP TABLE test_one_blob");
+} catch (Exception $e) {
+}
+
+$db->beginTransaction();
+
+$db->query('CREATE TABLE test_one_blob (id INT NOT NULL, blob1 BLOB)');
+
+$stmt = $db->prepare("INSERT INTO test_one_blob (id, blob1) VALUES (:id, EMPTY_BLOB()) RETURNING blob1 INTO :foo");
+
+$data = 'foo';
+$blob = fopen('php://memory', 'a');
+fwrite($blob, $data);
+rewind($blob);
+
+$id = 1;
+$stmt->bindparam(':id', $id);
+$stmt->bindparam(':foo', $blob, PDO::PARAM_LOB);
+$stmt->execute();
+
+$data = '';
+$blob = fopen('php://memory', 'a');
+fwrite($blob, $data);
+rewind($blob);
+
+$id = 1;
+$stmt->bindparam(':id', $id);
+$stmt->bindparam(':foo', $blob, PDO::PARAM_LOB);
+$stmt->execute();
+
+$res = $db->query("SELECT blob1 from test_one_blob");
+// Resource
+var_dump($res->fetch());
+
+// Empty string
+var_dump($res->fetch());
+
+$db->exec("DROP TABLE test_one_blob");
+
+?>
+--XFAIL--
+Corrupts memory
+--EXPECTF--
+array(2) {
+ ["blob1"]=>
+ string(3) "foo"
+ [0]=>
+ string(3) "foo"
+}
+array(2) {
+ ["blob1"]=>
+ string(0) ""
+ [0]=>
+ string(0) ""
+}
diff --git a/ext/pdo_oci/tests/bug46274_2.phpt b/ext/pdo_oci/tests/bug46274_2.phpt
new file mode 100644
index 0000000..9e92254
--- /dev/null
+++ b/ext/pdo_oci/tests/bug46274_2.phpt
@@ -0,0 +1,79 @@
+--TEST--
+Bug #46274 (pdo_pgsql - Segfault when using PDO::ATTR_STRINGIFY_FETCHES and blob)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci'))
+die('skip not loaded');
+require dirname(__FILE__).'/../../pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require 'ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
+
+try {
+ $db->exec("DROP TABLE test_one_blob");
+} catch (Exception $e) {
+}
+
+$db->beginTransaction();
+
+$db->query('CREATE TABLE test_one_blob (id INT NOT NULL, blob1 BLOB)');
+
+$stmt = $db->prepare("INSERT INTO test_one_blob (id, blob1) VALUES (:id, EMPTY_BLOB()) RETURNING blob1 INTO :foo");
+
+$data = 'foo';
+$blob = fopen('php://memory', 'a');
+fwrite($blob, $data);
+rewind($blob);
+
+$id = 1;
+$stmt->bindparam(':id', $id);
+$stmt->bindparam(':foo', $blob, PDO::PARAM_LOB);
+$stmt->execute();
+
+$data = '';
+$blob = fopen('php://memory', 'a');
+fwrite($blob, $data);
+rewind($blob);
+
+$id = 1;
+$stmt->bindparam(':id', $id);
+$stmt->bindparam(':foo', $blob, PDO::PARAM_LOB);
+$stmt->execute();
+
+$res = $db->query("SELECT blob1 from test_one_blob");
+// Resource
+var_dump($row = $res->fetch());
+var_dump(fread($row[0], 1024));
+fclose($row[0]);
+
+// Empty string
+var_dump($row = $res->fetch());
+var_dump(fread($row[0], 1024));
+fclose($row[0]);
+
+$db->exec("DROP TABLE test_one_blob");
+
+?>
+--XFAIL--
+Corrupts memory
+--EXPECTF--
+array(2) {
+ ["blob1"]=>
+ resource(%d) of type (stream)
+ [0]=>
+ resource(%d) of type (stream)
+}
+string(3) "foo"
+array(2) {
+ ["blob1"]=>
+ resource(%d) of type (stream)
+ [0]=>
+ resource(%d) of type (stream)
+}
+string(0) ""
diff --git a/ext/pdo_oci/tests/bug57702.phpt b/ext/pdo_oci/tests/bug57702.phpt
new file mode 100644
index 0000000..9281f6d
--- /dev/null
+++ b/ext/pdo_oci/tests/bug57702.phpt
@@ -0,0 +1,165 @@
+--TEST--
+PDO OCI Bug #57702 (Multi-row BLOB fetches)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require('ext/pdo/tests/pdo_test.inc');
+$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
+
+// Note the PDO test setup sets PDO::ATTR_STRINGIFY_FETCHES to true
+// (and sets PDO::ATTR_CASE to PDO::CASE_LOWER)
+
+$query = "begin execute immediate 'drop table mytable'; exception when others then if sqlcode <> -942 then raise; end if; end;";
+$stmt = $db->prepare($query);
+$stmt->execute();
+
+$query = "create table bug57702 (id number, data1 blob, data2 blob)";
+$stmt = $db->prepare($query);
+$stmt->execute();
+
+function do_insert($db, $id, $data1, $data2)
+{
+ $db->beginTransaction();
+ $stmt = $db->prepare("insert into bug57702 (id, data1, data2) values (:id, empty_blob(), empty_blob()) returning data1, data2 into :blob1, :blob2");
+ $stmt->bindParam(':id', $id);
+ $stmt->bindParam(':blob1', $blob1, PDO::PARAM_LOB);
+ $stmt->bindParam(':blob2', $blob2, PDO::PARAM_LOB);
+ $blob1 = null;
+ $blob2 = null;
+ $stmt->execute();
+
+ fwrite($blob1, $data1);
+ fclose($blob1);
+ fwrite($blob2, $data2);
+ fclose($blob2);
+ $db->commit();
+}
+
+do_insert($db, 1, "row 1 col 1", "row 1 col 2");
+do_insert($db, 2, "row 2 col 1", "row 2 col 2");
+
+////////////////////
+
+echo "First Query\n";
+
+// Fetch it back
+$stmt = $db->prepare('select data1, data2 from bug57702 order by id');
+$stmt->execute();
+$row = $stmt->fetch(PDO::FETCH_ASSOC);
+var_dump($row['data1']);
+var_dump($row['data2']);
+$row = $stmt->fetch(PDO::FETCH_ASSOC);
+var_dump($row['data1']);
+var_dump($row['data2']);
+
+////////////////////
+
+echo "\nSecond Query\n";
+
+foreach($db->query("select data1 as d1, data2 as d2 from bug57702 order by id") as $row) {
+ var_dump($row['d1']);
+ var_dump($row['d2']);
+}
+
+////////////////////
+
+echo "\nThird Query\n";
+
+$stmt = $db->prepare('select data1 as d3_1, data2 as d3_2 from bug57702 order by id');
+
+$rs = $stmt->execute();
+$stmt->bindColumn('d3_1' , $clob1, PDO::PARAM_LOB);
+$stmt->bindColumn('d3_2' , $clob2, PDO::PARAM_LOB);
+
+while ($stmt->fetch(PDO::FETCH_BOUND)) {
+ var_dump($clob1);
+ var_dump($clob2);
+}
+print "done\n";
+
+////////////////////
+
+echo "\nFourth Query\n";
+
+$a = array();
+$i = 0;
+foreach($db->query("select data1 as d4_1, data2 as d4_2 from bug57702 order by id") as $row) {
+ $a[$i][0] = $row['d4_1'];
+ $a[$i][1] = $row['d4_2'];
+ $i++;
+}
+
+for ($i = 0; $i < count($a); $i++) {
+ var_dump($a[$i][0]);
+ var_dump($a[$i][1]);
+}
+
+////////////////////
+
+echo "\nFifth Query\n";
+
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); // Let's use streams
+
+// Since each column only has one lob descriptor, the last row is
+// shown twice because the lob descriptor for each column is reused in
+// the stream
+
+$a = array();
+$i = 0;
+foreach($db->query("select data1 as d4_1, data2 as d4_2 from bug57702 order by id") as $row) {
+ $a[$i][0] = $row['d4_1'];
+ $a[$i][1] = $row['d4_2'];
+ $i++;
+}
+
+for ($i = 0; $i < count($a); $i++) {
+ var_dump(stream_get_contents($a[$i][0]));
+ var_dump(stream_get_contents($a[$i][1]));
+}
+
+// Cleanup
+$query = "drop table bug57702";
+$stmt = $db->prepare($query);
+$stmt->execute();
+
+print "done\n";
+
+?>
+--EXPECTF--
+First Query
+string(11) "row 1 col 1"
+string(11) "row 1 col 2"
+string(11) "row 2 col 1"
+string(11) "row 2 col 2"
+
+Second Query
+string(11) "row 1 col 1"
+string(11) "row 1 col 2"
+string(11) "row 2 col 1"
+string(11) "row 2 col 2"
+
+Third Query
+string(11) "row 1 col 1"
+string(11) "row 1 col 2"
+string(11) "row 2 col 1"
+string(11) "row 2 col 2"
+done
+
+Fourth Query
+string(11) "row 1 col 1"
+string(11) "row 1 col 2"
+string(11) "row 2 col 1"
+string(11) "row 2 col 2"
+
+Fifth Query
+string(11) "row 2 col 1"
+string(11) "row 2 col 2"
+string(11) "row 2 col 1"
+string(11) "row 2 col 2"
+done
diff --git a/ext/pdo_oci/tests/bug_33707.phpt b/ext/pdo_oci/tests/bug_33707.phpt
new file mode 100644
index 0000000..1ac9fa4
--- /dev/null
+++ b/ext/pdo_oci/tests/bug_33707.phpt
@@ -0,0 +1,29 @@
+--TEST--
+PDO OCI Bug #33707 (Errors in select statements not reported)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require dirname(__FILE__).'/../../pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require 'ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
+
+$rs = $db->query('select blah from a_table_that_doesnt_exist');
+var_dump($rs);
+var_dump($db->errorInfo());
+
+--EXPECTF--
+bool(false)
+array(3) {
+ [0]=>
+ string(5) "HY000"
+ [1]=>
+ int(942)
+ [2]=>
+ string(%d) "OCIStmtExecute: ORA-00942: table or view does not exist
+ (%s:%d)"
+}
diff --git a/ext/pdo_oci/tests/common.phpt b/ext/pdo_oci/tests/common.phpt
new file mode 100644
index 0000000..5107828
--- /dev/null
+++ b/ext/pdo_oci/tests/common.phpt
@@ -0,0 +1,26 @@
+--TEST--
+OCI
+--SKIPIF--
+<?php # vim:ft=php
+if (!extension_loaded('pdo_oci')) print 'skip'; ?>
+--REDIRECTTEST--
+# magic auto-configuration
+
+$config = array(
+ 'TESTS' => 'ext/pdo/tests'
+);
+
+
+if (false !== getenv('PDO_OCI_TEST_DSN')) {
+ # user set them from their shell
+ $config['ENV']['PDOTEST_DSN'] = getenv('PDO_OCI_TEST_DSN');
+ $config['ENV']['PDOTEST_USER'] = getenv('PDO_OCI_TEST_USER');
+ $config['ENV']['PDOTEST_PASS'] = getenv('PDO_OCI_TEST_PASS');
+ $config['ENV']['PDOTEST_ATTR'] = getenv('PDO_OCI_TEST_ATTR');
+} else {
+ $config['ENV']['PDOTEST_DSN'] = 'oci:dbname=localhost/xe;charset=WE8MSWIN1252';
+ $config['ENV']['PDOTEST_USER'] = 'SYSTEM';
+ $config['ENV']['PDOTEST_PASS'] = 'oracle';
+}
+
+return $config;
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_autocommit_1.phpt b/ext/pdo_oci/tests/pdo_oci_attr_autocommit_1.phpt
new file mode 100644
index 0000000..298d59e
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_autocommit_1.phpt
@@ -0,0 +1,64 @@
+--TEST--
+PDO_OCI: Attribute: Basic autocommit functionality
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
+$dbh->exec("drop table pdo_ac_tab");
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+print "PDO::ATTR_AUTOCOMMIT: Default: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+
+echo "Change setting to false - ";
+
+$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
+
+print "PDO::ATTR_AUTOCOMMIT: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+
+echo "Change setting back to true - ";
+
+$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
+
+print "PDO::ATTR_AUTOCOMMIT: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+
+// Use 2nd connection to check that autocommit does commit
+
+echo "Insert data\n";
+$dbh->exec("create table pdo_ac_tab (col1 varchar2(20))");
+$dbh->exec("insert into pdo_ac_tab (col1) values ('some data')");
+
+$dbh2 = PDOTest::factory();
+
+echo "Second connection should be able to see committed data\n";
+$s = $dbh2->prepare("select col1 from pdo_ac_tab");
+$s->execute();
+while ($r = $s->fetch()) {
+ echo "Data is: " . $r[0] . "\n";
+}
+
+$dbh->exec("drop table pdo_ac_tab");
+
+echo "Done\n";
+
+?>
+--EXPECT--
+PDO::ATTR_AUTOCOMMIT: Default: bool(true)
+Change setting to false - PDO::ATTR_AUTOCOMMIT: bool(false)
+Change setting back to true - PDO::ATTR_AUTOCOMMIT: bool(true)
+Insert data
+Second connection should be able to see committed data
+Data is: some data
+Done \ No newline at end of file
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_autocommit_2.phpt b/ext/pdo_oci/tests/pdo_oci_attr_autocommit_2.phpt
new file mode 100644
index 0000000..9addca8
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_autocommit_2.phpt
@@ -0,0 +1,127 @@
+--TEST--
+PDO_OCI: Attribute: beginTransaction and native transactions
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+$dbh = PDOTest::factory();
+
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
+$dbh->exec("drop table pdo_ac_tab");
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+$dbh->exec("create table pdo_ac_tab (col1 varchar2(25))");
+
+echo "Test 1 Check beginTransaction insertion\n";
+
+$dbh->beginTransaction();
+try {
+ $dbh->exec("insert into pdo_ac_tab (col1) values ('data 1')");
+ $dbh->exec("insert into pdo_ac_tab (col1) values ('data 2')");
+ $dbh->commit();
+}
+catch (PDOException $e) {
+ echo "Caught unexpected exception at line " . __LINE__ . "\n";
+ echo $e->getMessage() . "\n";
+ $dbh->rollback();
+}
+
+echo "Test 2 Cause an exception and test beginTransaction rollback\n";
+
+$dbh->beginTransaction();
+try {
+ $dbh->exec("insert into pdo_ac_tab (col1) values ('not committed #1')");
+ $dbh->exec("insert into pdo_ac_tab (col1) values ('data that is too long to fit and will barf')");
+ $dbh->commit();
+}
+catch (PDOException $e) {
+ echo "Caught expected exception at line " . __LINE__ . "\n";
+ echo $e->getMessage() . "\n";
+ $dbh->rollback();
+}
+
+echo "Test 3 Setting ATTR_AUTOCOMMIT to true will commit and end the transaction\n";
+
+$dbh->exec("insert into pdo_ac_tab (col1) values ('data 3')");
+$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
+print "PDO::ATTR_AUTOCOMMIT: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+try {
+ $dbh->rollback();
+}
+catch (PDOException $e) {
+ echo "Caught expected exception at line " . __LINE__ . "\n";
+ echo $e->getMessage() . "\n";
+}
+
+echo "Test 4 Setting ATTR_AUTOCOMMIT to false will commit and end the transaction\n";
+
+$dbh->beginTransaction();
+$dbh->exec("insert into pdo_ac_tab (col1) values ('data 4')");
+$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
+print "PDO::ATTR_AUTOCOMMIT: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+try {
+ $dbh->rollback();
+}
+catch (PDOException $e) {
+ echo "Caught expected exception at line " . __LINE__ . "\n";
+ echo $e->getMessage() . "\n";
+}
+
+echo "Test 5 Handle transactions ourselves\n";
+
+print "PDO::ATTR_AUTOCOMMIT: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+
+$dbh->exec("insert into pdo_ac_tab (col1) values ('not committed #2')");
+$dbh->exec("rollback");
+$dbh->exec("insert into pdo_ac_tab (col1) values ('data 5')");
+$dbh->exec("insert into pdo_ac_tab (col1) values ('data 6')");
+
+$dbh->exec("commit");
+
+// Open new connection to really verify what was inserted
+
+$dbh2 = PDOTest::factory();
+
+echo "Query Results are:\n";
+$s = $dbh2->prepare("select col1 from pdo_ac_tab");
+$s->execute();
+while ($r = $s->fetch()) {
+ echo $r[0] . "\n";
+}
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Test 1 Check beginTransaction insertion
+Test 2 Cause an exception and test beginTransaction rollback
+Caught expected exception at line 35
+SQLSTATE[HY000]: General error: 12899 OCIStmtExecute: ORA-12899: %s
+%s
+Test 3 Setting ATTR_AUTOCOMMIT to true will commit and end the transaction
+PDO::ATTR_AUTOCOMMIT: bool(true)
+Caught expected exception at line %d
+There is no active transaction
+Test 4 Setting ATTR_AUTOCOMMIT to false will commit and end the transaction
+PDO::ATTR_AUTOCOMMIT: bool(false)
+Caught expected exception at line %d
+There is no active transaction
+Test 5 Handle transactions ourselves
+PDO::ATTR_AUTOCOMMIT: bool(false)
+Query Results are:
+data 1
+data 2
+data 3
+data 4
+data 5
+data 6
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_autocommit_3.phpt b/ext/pdo_oci/tests/pdo_oci_attr_autocommit_3.phpt
new file mode 100644
index 0000000..81e9b74
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_autocommit_3.phpt
@@ -0,0 +1,51 @@
+--TEST--
+PDO_OCI: Atrribute: closing a connection in non-autocommit mode commits data
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+// Check connection can be created with AUTOCOMMIT off
+putenv('PDOTEST_ATTR='.serialize(array(PDO::ATTR_AUTOCOMMIT=>false)));
+$dbh = PDOTest::factory();
+
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
+$dbh->exec("drop table pdo_ac_tab");
+
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+print "PDO::ATTR_AUTOCOMMIT: ";
+var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
+
+echo "Insert data\n";
+
+$dbh->exec("create table pdo_ac_tab (col1 varchar2(20))");
+
+$dbh->exec("insert into pdo_ac_tab (col1) values ('some data')");
+
+$dbh = null; // close first connection
+
+echo "Second connection should be able to see committed data\n";
+$dbh2 = PDOTest::factory();
+$s = $dbh2->prepare("select col1 from pdo_ac_tab");
+$s->execute();
+while ($r = $s->fetch()) {
+ echo "Data is: " . $r[0] . "\n";
+}
+
+$dbh2->exec("drop table pdo_ac_tab");
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+PDO::ATTR_AUTOCOMMIT: bool(false)
+Insert data
+Second connection should be able to see committed data
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_case.phpt b/ext/pdo_oci/tests/pdo_oci_attr_case.phpt
new file mode 100644
index 0000000..4c19d6c
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_case.phpt
@@ -0,0 +1,81 @@
+--TEST--
+PDO_OCI: Attribute: Column Case
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+function do_query1($dbh)
+{
+ var_dump($dbh->getAttribute(PDO::ATTR_CASE));
+ $s = $dbh->prepare("select dummy from dual");
+ $s->execute();
+ while ($r = $s->fetch(PDO::FETCH_ASSOC)) {
+ var_dump($r);
+ }
+}
+
+function do_query2($dbh, $mode)
+{
+ echo "Mode desired is $mode\n";
+ $s = $dbh->prepare("select dummy from dual", array(PDO::ATTR_CASE, $mode));
+ $s->execute();
+ while ($r = $s->fetch(PDO::FETCH_ASSOC)) {
+ var_dump($r);
+ }
+}
+
+$dbh = PDOTest::factory();
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+echo "Test 1 - Force column names to lower case\n";
+$dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
+do_query1($dbh);
+
+echo "Test 2 - Leave column names as returned by the database driver\n";
+$dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
+do_query1($dbh);
+
+echo "Test 3 - Force column names to upper case\n";
+$dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
+do_query1($dbh);
+
+echo "Test 4 - Setting on statement has no effect. Attempt lower case but get upper\n";
+$dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL); // reset
+do_query2($dbh, PDO::CASE_LOWER);
+
+echo "Done\n";
+
+?>
+--EXPECT--
+Test 1 - Force column names to lower case
+int(2)
+array(1) {
+ ["dummy"]=>
+ string(1) "X"
+}
+Test 2 - Leave column names as returned by the database driver
+int(0)
+array(1) {
+ ["DUMMY"]=>
+ string(1) "X"
+}
+Test 3 - Force column names to upper case
+int(1)
+array(1) {
+ ["DUMMY"]=>
+ string(1) "X"
+}
+Test 4 - Setting on statement has no effect. Attempt lower case but get upper
+Mode desired is 2
+array(1) {
+ ["DUMMY"]=>
+ string(1) "X"
+}
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_client.phpt b/ext/pdo_oci/tests/pdo_oci_attr_client.phpt
new file mode 100644
index 0000000..372ccec
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_client.phpt
@@ -0,0 +1,43 @@
+--TEST--
+PDO_OCI: Attribute: Client version
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+echo "ATTR_CLIENT_VERSION: ";
+$cv = $dbh->getAttribute(PDO::ATTR_CLIENT_VERSION);
+var_dump($cv);
+
+$s = explode(".", $cv);
+if ($s[0] >= 10 && count($s) > 1 && $s[1] >= 2) {
+ if (count($s) != 5) {
+ echo "Wrong number of values in array\nVersion was: ";
+ var_dump($cv);
+ } else {
+ echo "Version OK, so far as can be portably checked\n";
+ }
+} else {
+ if (count($s) != 2) {
+ echo "Wrong number of values in array\nVersion was: ";
+ var_dump($cv);
+ } else {
+ echo "Version OK, so far as can be portably checked\n";
+ }
+}
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+ATTR_CLIENT_VERSION: string(%d) "%d.%s"
+Version OK, so far as can be portably checked
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_drivername.phpt b/ext/pdo_oci/tests/pdo_oci_attr_drivername.phpt
new file mode 100644
index 0000000..7934e79
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_drivername.phpt
@@ -0,0 +1,21 @@
+--TEST--
+PDO_OCI: Attribute: verify driver name
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc';
+
+$dbh = PDOTest::factory();
+var_dump($dbh->getAttribute(PDO::ATTR_DRIVER_NAME));
+
+echo "Done\n";
+?>
+--EXPECT--
+string(3) "oci"
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_nulls_1.phpt b/ext/pdo_oci/tests/pdo_oci_attr_nulls_1.phpt
new file mode 100644
index 0000000..b9c4612
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_nulls_1.phpt
@@ -0,0 +1,61 @@
+--TEST--
+PDO_OCI: Attribute: Oracle Nulls
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+function do_query($dbh)
+{
+ var_dump($dbh->getAttribute(PDO::ATTR_ORACLE_NULLS));
+ $s = $dbh->prepare("select '' as myempty, null as mynull from dual");
+ $s->execute();
+ while ($r = $s->fetch()) {
+ var_dump($r[0]);
+ var_dump($r[1]);
+ }
+}
+
+$dbh = PDOTest::factory();
+
+print "PDO::ATTR_ORACLE_NULLS: Default: ";
+do_query($dbh);
+
+print "PDO::ATTR_ORACLE_NULLS: PDO::NULL_NATURAL: ";
+$dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL); // No conversion.
+
+do_query($dbh);
+
+print "PDO::ATTR_ORACLE_NULLS: PDO::NULL_EMPTY_STRING: ";
+$dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); // Empty string is converted to NULL.
+
+do_query($dbh);
+
+print "PDO::ATTR_ORACLE_NULLS: PDO::NULL_TO_STRING: ";
+$dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_TO_STRING); // NULL is converted to an empty string.
+
+do_query($dbh);
+
+echo "Done\n";
+
+?>
+--EXPECT--
+PDO::ATTR_ORACLE_NULLS: Default: int(0)
+NULL
+NULL
+PDO::ATTR_ORACLE_NULLS: PDO::NULL_NATURAL: int(0)
+NULL
+NULL
+PDO::ATTR_ORACLE_NULLS: PDO::NULL_EMPTY_STRING: int(1)
+NULL
+NULL
+PDO::ATTR_ORACLE_NULLS: PDO::NULL_TO_STRING: int(2)
+string(0) ""
+string(0) ""
+Done \ No newline at end of file
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_prefetch_1.phpt b/ext/pdo_oci/tests/pdo_oci_attr_prefetch_1.phpt
new file mode 100644
index 0000000..839fe83
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_prefetch_1.phpt
@@ -0,0 +1,37 @@
+--TEST--
+PDO_OCI: Attribute: Set prefetch on connection
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+echo "Test connect: (value is ignored & has no effect)\n";
+putenv('PDOTEST_ATTR='.serialize(array(PDO::ATTR_PREFETCH=>101)));
+$dbh = PDOTest::factory();
+
+echo "Test set: (value is ignored & has no effect)\n";
+$dbh->setAttribute(PDO::ATTR_PREFETCH, 102);
+
+// Verify can fetch
+$s = $dbh->prepare("select dummy from dual" );
+$s->execute();
+while ($r = $s->fetch()) {
+ echo $r[0] . "\n";
+}
+
+echo "Done\n";
+
+?>
+--EXPECT--
+Test connect: (value is ignored & has no effect)
+Test set: (value is ignored & has no effect)
+X
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_prefetch_2.phpt b/ext/pdo_oci/tests/pdo_oci_attr_prefetch_2.phpt
new file mode 100644
index 0000000..4b8fd80
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_prefetch_2.phpt
@@ -0,0 +1,47 @@
+--TEST--
+PDO_OCI: Attribute: prefetch on statements
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+$s = $dbh->prepare("select '' as myempty, null as mynull from dual", array(PDO::ATTR_PREFETCH => 101));
+
+echo "Test 1: Can't set prefetch after prepare\n";
+var_dump($s->setAttribute(PDO::ATTR_PREFETCH, 102));
+
+// Verify can fetch
+$s = $dbh->prepare("select dummy from dual" );
+$s->execute();
+while ($r = $s->fetch()) {
+ echo $r[0] . "\n";
+}
+
+echo "Test 2: Turn off prefetching\n";
+$s = $dbh->prepare("select '' as myempty, null as mynull from dual", array(PDO::ATTR_PREFETCH => 0));
+$s = $dbh->prepare("select dummy from dual" );
+$s->execute();
+while ($r = $s->fetch()) {
+ echo $r[0] . "\n";
+}
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Test 1: Can't set prefetch after prepare
+
+Warning: PDOStatement::setAttribute(): SQLSTATE[IM001]: Driver does not support this function: This driver doesn't support setting attributes in %s on line %d
+bool(false)
+X
+Test 2: Turn off prefetching
+X
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_attr_server.phpt b/ext/pdo_oci/tests/pdo_oci_attr_server.phpt
new file mode 100644
index 0000000..dba5a19
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_attr_server.phpt
@@ -0,0 +1,40 @@
+--TEST--
+PDO_OCI: Attribute: Server version and info
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+echo "Test 1\n";
+echo "ATTR_SERVER_VERSION: ";
+var_dump($dbh->getAttribute(PDO::ATTR_SERVER_VERSION));
+
+echo "Test 2\n";
+echo "ATTR_SERVER_INFO\n";
+$si = $dbh->getAttribute(PDO::ATTR_SERVER_INFO);
+$pos = strpos($si, "Oracle");
+if ($pos === 0) {
+ echo "Found 'Oracle' at position $pos as expected\n";
+} else {
+ echo "Unexpected result. Server info was:\n";
+ var_dump($si);
+}
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Test 1
+ATTR_SERVER_VERSION: string(%d) "%d.%d.%d.%d.%d"
+Test 2
+ATTR_SERVER_INFO
+Found 'Oracle' at position 0 as expected
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_fread_1.phpt b/ext/pdo_oci/tests/pdo_oci_fread_1.phpt
new file mode 100644
index 0000000..26a92f0
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_fread_1.phpt
@@ -0,0 +1,60 @@
+--TEST--
+PDO_OCI: check fread() EOF
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+if (!strpos(strtolower(getenv('PDOTEST_DSN')), 'charset=we8mswin1252')) die('skip expected output valid for WE8MSWIN1252 character set');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+$dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
+
+// Initialization
+$stmtarray = array(
+ "begin execute immediate 'drop table pdo_oci_fread_tab'; exception when others then null; end;",
+ "create table pdo_oci_fread_tab (id number, data clob)",
+ "declare
+ lob1 clob := 'abc' || lpad('j',4020,'j') || 'xyz';
+ begin
+ insert into pdo_oci_fread_tab (id,data) values (1, lob1);
+ end;"
+);
+
+foreach ($stmtarray as $stmt) {
+ $dbh->exec($stmt);
+}
+
+echo "Test 1\n";
+
+$s = $dbh->query("select data from pdo_oci_fread_tab where id = 1");
+$r = $s->fetch();
+$sh = $r['data'];
+
+while (!feof($sh)) {
+ $buffer = fread($sh,1024);
+ echo '*'.$buffer.'*';
+}
+echo "\n";
+fclose($sh);
+
+// Clean up
+
+$stmtarray = array(
+ "drop table pdo_oci_fread_tab"
+);
+
+foreach ($stmtarray as $stmt) {
+ $dbh->exec($stmt);
+}
+
+?>
+--EXPECTF--
+Test 1
+*abcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj**jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj**jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj**jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjxyz*
diff --git a/ext/pdo_oci/tests/pdo_oci_quote1.phpt b/ext/pdo_oci/tests/pdo_oci_quote1.phpt
new file mode 100644
index 0000000..d92317f
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_quote1.phpt
@@ -0,0 +1,163 @@
+--TEST--
+Test PDO->quote() for PDO_OCI
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc';
+$db = PDOTest::factory();
+
+@$db->exec("drop table poq_tab");
+$db->query("create table poq_tab (t varchar2(100))");
+$stmt = $db->prepare('select * from poq_tab');
+
+// The intent is that the fetched data be identical to the unquoted string.
+// Remember!: use bind variables instead of PDO->quote()
+
+$a = array(null, "", "a", "ab", "abc", "ab'cd", "a\b\n", "'", "''", "a'", "'z", "a''b", '"');
+foreach ($a as $u) {
+ $q = $db->quote($u);
+ echo "Unquoted : ";
+ var_dump($u);
+ echo "Quoted : ";
+ var_dump($q);
+
+ $db->exec("delete from poq_tab");
+
+ $db->query("insert into poq_tab (t) values($q)");
+ $stmt->execute();
+ var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+}
+
+echo "Done\n";
+
+@$db->exec("drop table poq_tab");
+
+?>
+--EXPECTF--
+Unquoted : NULL
+Quoted : string(2) "''"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ NULL
+ }
+}
+Unquoted : string(0) ""
+Quoted : string(2) "''"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ NULL
+ }
+}
+Unquoted : string(1) "a"
+Quoted : string(3) "'a'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(1) "a"
+ }
+}
+Unquoted : string(2) "ab"
+Quoted : string(4) "'ab'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(2) "ab"
+ }
+}
+Unquoted : string(3) "abc"
+Quoted : string(5) "'abc'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(3) "abc"
+ }
+}
+Unquoted : string(5) "ab'cd"
+Quoted : string(8) "'ab''cd'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(5) "ab'cd"
+ }
+}
+Unquoted : string(4) "a\b
+"
+Quoted : string(6) "'a\b
+'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(4) "a\b
+"
+ }
+}
+Unquoted : string(1) "'"
+Quoted : string(4) "''''"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(1) "'"
+ }
+}
+Unquoted : string(2) "''"
+Quoted : string(6) "''''''"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(2) "''"
+ }
+}
+Unquoted : string(2) "a'"
+Quoted : string(5) "'a'''"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(2) "a'"
+ }
+}
+Unquoted : string(2) "'z"
+Quoted : string(5) "'''z'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(2) "'z"
+ }
+}
+Unquoted : string(4) "a''b"
+Quoted : string(8) "'a''''b'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(4) "a''b"
+ }
+}
+Unquoted : string(1) """
+Quoted : string(3) "'"'"
+array(1) {
+ [0]=>
+ array(1) {
+ ["t"]=>
+ string(1) """
+ }
+}
+Done
diff --git a/ext/pdo_oci/tests/pdo_oci_stream_1.phpt b/ext/pdo_oci/tests/pdo_oci_stream_1.phpt
new file mode 100644
index 0000000..27a28b9
--- /dev/null
+++ b/ext/pdo_oci/tests/pdo_oci_stream_1.phpt
@@ -0,0 +1,113 @@
+--TEST--
+PDO_OCI: stream_get_contents length & offset test
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+if (!strpos(strtolower(getenv('PDOTEST_DSN')), 'charset=we8mswin1252')) die('skip expected output valid for WE8MSWIN1252 character set');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require(dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc');
+
+$dbh = PDOTest::factory();
+
+$dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
+
+// Initialization
+@$dbh->exec("drop table pdo_oci_stream_1_tab");
+
+$stmtarray = array(
+ "create table pdo_oci_stream_1_tab (id number, data clob)",
+);
+
+foreach ($stmtarray as $stmt) {
+ $dbh->exec($stmt);
+}
+
+$dbh->exec("
+ declare
+ lob1 clob := 'abc' || lpad('j',30000,'j') || 'xyz';
+ begin
+ insert into pdo_oci_stream_1_tab (id,data) values (1, 'abcdefghijklmnopqrstuvwxyz');
+ insert into pdo_oci_stream_1_tab (id,data) values (2, lob1);
+ end;");
+
+echo "Test 1\n";
+
+$s = $dbh->prepare("select data from pdo_oci_stream_1_tab where id = 1");
+$s->execute();
+$r = $s->fetch();
+
+// stream_get_contents ( resource $handle [, int $maxlength = -1 [, int $offset = -1 ]] )
+echo 'Read '.stream_get_contents($r['data'], 1, 1)."$\n"; // b
+echo 'Read '.stream_get_contents($r['data'], 2, 1)."$\n"; // cd
+echo 'Read '.stream_get_contents($r['data'], 2, 0)."$\n"; // ab
+echo 'Read '.stream_get_contents($r['data'], 26, 0)."$\n"; // abcdefghijklmnopqrstuvwxyz
+echo 'Read '.stream_get_contents($r['data'], 27, 0)."$\n"; // abcdefghijklmnopqrstuvwxyz
+echo 'Read '.stream_get_contents($r['data'], 27, 1)."$\n"; // bcdefghijklmnopqrstuvwxyz
+echo 'Read '.stream_get_contents($r['data'], 1, 20)."$\n"; // u
+echo 'Read '.stream_get_contents($r['data'], 1, 25)."$\n"; // z
+echo 'Read '.stream_get_contents($r['data'], 1, 26)."$\n"; // <blank>
+echo 'Read '.stream_get_contents($r['data'], 1, 0)."$\n"; // a
+
+echo "\nTest 2\n";
+
+$s = $dbh->prepare("select data from pdo_oci_stream_1_tab where id = 2");
+$s->execute();
+$r = $s->fetch();
+
+echo 'Read '.stream_get_contents($r['data'], 5, 0)."\n"; // abcjj
+echo 'Read '.stream_get_contents($r['data'], 5, 2)."\n"; // cjjjj
+echo 'Read '.stream_get_contents($r['data'], 6, 1)."\n"; // bcjjjj
+echo 'Read '.strlen(stream_get_contents($r['data'], -1,0))."\n"; // 30006
+echo 'Read '.strlen(stream_get_contents($r['data'], 0,0))."\n"; // 0
+echo 'Read '.strlen(stream_get_contents($r['data'], 0,1))."\n"; // 0
+echo 'Read '.strlen(stream_get_contents($r['data'], 10,100))."\n"; // 10
+echo 'Read '.stream_get_contents($r['data'], 6, 30000)."\n"; // jjjxyz
+echo 'Read '.stream_get_contents($r['data'], 7, 30000)."\n"; // jjjxyz
+echo 'Read '.strlen(stream_get_contents($r['data']))."\n"; // 0
+echo 'Read '.strlen(stream_get_contents($r['data'], 0))."\n"; // 0
+echo 'Read '.strlen(stream_get_contents($r['data'], -1))."\n"; // 0
+echo 'Read '.stream_get_contents($r['data'], -1, 30000)."\n"; // jjjxyz
+
+// Clean up
+
+$stmtarray = array(
+ "drop table pdo_oci_stream_1_tab"
+);
+
+foreach ($stmtarray as $stmt) {
+ $dbh->exec($stmt);
+}
+
+?>
+--EXPECTF--
+Test 1
+Read b$
+Read cd$
+Read ab$
+Read abcdefghijklmnopqrstuvwxyz$
+Read abcdefghijklmnopqrstuvwxyz$
+Read bcdefghijklmnopqrstuvwxyz$
+Read u$
+Read z$
+Read $
+Read a$
+
+Test 2
+Read abcjj
+Read cjjjj
+Read bcjjjj
+Read 30006
+Read 0
+Read 0
+Read 10
+Read jjjxyz
+Read jjjxyz
+Read 0
+Read 0
+Read 0
+Read jjjxyz \ No newline at end of file
diff --git a/ext/pdo_oci/tests/pecl_bug_11345.phpt b/ext/pdo_oci/tests/pecl_bug_11345.phpt
new file mode 100644
index 0000000..b80773a
--- /dev/null
+++ b/ext/pdo_oci/tests/pecl_bug_11345.phpt
@@ -0,0 +1,29 @@
+--TEST--
+PECL PDO_OCI Bug #11345 (Test invalid character set name)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+// This tests only part of PECL bug 11345. The other part - testing
+// when the National Language Support (NLS) environment can't be
+// initialized - is very difficult to test portably.
+
+try {
+ $dbh = new PDO('oci:dbname=xxx;charset=yyy', 'abc', 'def');
+}
+catch (PDOException $e) {
+ echo 'Connection failed: ' . $e->getMessage(). "\n";
+ exit;
+}
+
+echo "Done\n";
+
+?>
+
+--EXPECTF--
+Connection failed: SQLSTATE[HY000]: OCINlsCharSetNameToId: unknown character set name (%s) \ No newline at end of file
diff --git a/ext/pdo_oci/tests/pecl_bug_6364.phpt b/ext/pdo_oci/tests/pecl_bug_6364.phpt
new file mode 100644
index 0000000..b2981ec
--- /dev/null
+++ b/ext/pdo_oci/tests/pecl_bug_6364.phpt
@@ -0,0 +1,71 @@
+--TEST--
+PECL PDO_OCI Bug #6364 (segmentation fault on stored procedure call with OUT binds)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_oci')) die('skip not loaded');
+require(dirname(__FILE__).'/../../pdo/tests/pdo_test.inc');
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../pdo/tests/pdo_test.inc';
+$dbh = PDOTest::factory();
+
+@$dbh->exec ("drop table bug_6364_t");
+
+$dbh->exec ("create table bug_6364_t (c1 varchar2(10), c2 varchar2(10), c3 varchar2(10), c4 varchar2(10), c5 varchar2(10))");
+
+$dbh->exec ("create or replace procedure bug_6364_sp(p1 IN varchar2, p2 IN varchar2, p3 IN varchar2, p4 OUT varchar2, p5 OUT varchar2) as begin insert into bug_6364_t (c1, c2, c3) values (p1, p2, p3); p4 := 'val4'; p5 := 'val5'; end;");
+
+$stmt = $dbh->prepare("call bug_6364_sp('p1','p2','p3',?,?)");
+
+$out_param1 = "a";
+$out_param2 = "a";
+
+$stmt->bindParam(1, $out_param1,PDO::PARAM_STR, 1024);
+$stmt->bindParam(2, $out_param2,PDO::PARAM_STR, 1024);
+
+$stmt->execute() or die ("Execution error: " . var_dump($dbh->errorInfo()));
+
+var_dump($out_param1);
+var_dump($out_param2);
+
+foreach ($dbh->query("select * from bug_6364_t") as $row) {
+ var_dump($row);
+}
+
+print "Done\n";
+
+// Cleanup
+$dbh->exec ("drop procedure bug_6364_sp");
+$dbh->exec ("drop table bug_6364_t");
+
+?>
+
+--EXPECTF--
+string(4) "val4"
+string(4) "val5"
+array(10) {
+ ["c1"]=>
+ string(2) "p1"
+ [0]=>
+ string(2) "p1"
+ ["c2"]=>
+ string(2) "p2"
+ [1]=>
+ string(2) "p2"
+ ["c3"]=>
+ string(2) "p3"
+ [2]=>
+ string(2) "p3"
+ ["c4"]=>
+ NULL
+ [3]=>
+ NULL
+ ["c5"]=>
+ NULL
+ [4]=>
+ NULL
+}
+Done