Initial import from PHP

This commit is contained in:
Derick Rethans
2024-02-05 11:04:21 +00:00
commit bc6545aab1
46 changed files with 5341 additions and 0 deletions

2
CREDITS Normal file
View File

@@ -0,0 +1,2 @@
Oracle (OCI) driver for PDO
Wez Furlong

68
LICENSE Normal file
View File

@@ -0,0 +1,68 @@
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2024 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact group@php.net.
4. Products derived from this software may not be called "PHP", nor
may "PHP" appear in their name, without prior written permission
from group@php.net. You may indicate that your software works in
conjunction with PHP by saying "Foo for PHP" instead of calling
it "PHP Foo" or "phpfoo"
5. The PHP Group may publish revised and/or new versions of the
license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the terms
of that version. You may also choose to use such covered code
under the terms of any subsequent version of the license
published by the PHP Group. No one other than the PHP Group has
the right to modify the terms applicable to covered code created
under this License.
6. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes PHP software, freely available from
<http://www.php.net/software/>".
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------
This software consists of voluntary contributions made by many
individuals on behalf of the PHP Group.
The PHP Group can be contacted via Email at group@php.net.
For more information on the PHP Group and the PHP project,
please see <http://www.php.net>.
PHP includes the Zend Engine, freely available at
<http://www.zend.com>.

204
config.m4 Normal file
View File

@@ -0,0 +1,204 @@
if test -z "$SED"; then
PHP_PDO_OCI_SED="sed";
else
PHP_PDO_OCI_SED="$SED";
fi
PHP_PDO_OCI_TAIL1=`echo a | tail -n1 2>/dev/null`
if test "$PHP_PDO_OCI_TAIL1" = "a"; then
PHP_PDO_OCI_TAIL1="tail -n1"
else
PHP_PDO_OCI_TAIL1="tail -1"
fi
AC_DEFUN([AC_PDO_OCI_VERSION],[
AC_MSG_CHECKING([Oracle version])
PDO_OCI_LCS_BASE=$PDO_OCI_LIB_DIR/libclntsh.$SHLIB_SUFFIX_NAME
dnl Oracle 10g, 11g, 12c etc
PDO_OCI_LCS=`ls $PDO_OCI_LCS_BASE.*.1 2> /dev/null | $PHP_PDO_OCI_TAIL1`
if test -f "$PDO_OCI_LCS"; then
dnl Oracle 10g, 11g 12c etc. The x.2 version libraries are named x.1 for
dnl drop in compatibility
PDO_OCI_VERSION=`echo $PDO_OCI_LCS | $PHP_PDO_OCI_SED -e 's/.*\.\(.*\)\.1$/\1.1/'`
elif test -f $PDO_OCI_LCS_BASE.9.0; then
dnl There is no case for Oracle 9.2. Oracle 9.2 libraries have a 9.0 suffix
dnl for drop-in compatibility with Oracle 9.0
PDO_OCI_VERSION=9.0
else
AC_MSG_ERROR(Oracle libclntsh.$SHLIB_SUFFIX_NAME client library not found or its version is lower than 9)
fi
AC_MSG_RESULT($PDO_OCI_VERSION)
])
AC_DEFUN([AC_PDO_OCI_CHECK_LIB_DIR],[
AC_CHECK_SIZEOF([long])
AC_MSG_CHECKING([if we're at 64-bit platform])
AS_IF([test "$ac_cv_sizeof_long" -eq 4],[
AC_MSG_RESULT([no])
TMP_PDO_OCI_LIB_DIR="$PDO_OCI_DIR/lib32"
],[
AC_MSG_RESULT([yes])
TMP_PDO_OCI_LIB_DIR="$PDO_OCI_DIR/lib"
])
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],
[AS_HELP_STRING([[--with-pdo-oci[=DIR]]],
[PDO: Oracle OCI support. DIR defaults to $ORACLE_HOME. Use
--with-pdo-oci=instantclient,/path/to/instant/client/lib for an Oracle
Instant Client installation.])])
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])
AC_MSG_CHECKING([if we're at 64-bit platform])
AS_IF([test "$ac_cv_sizeof_long" -eq 4],[
AC_MSG_RESULT([no])
PDO_OCI_CLIENT_DIR="client"
],[
AC_MSG_RESULT([yes])
PDO_OCI_CLIENT_DIR="client64"
])
PDO_OCI_LIB_DIR="`echo $PDO_OCI_DIR | cut -d, -f2`"
AC_PDO_OCI_VERSION($PDO_OCI_LIB_DIR)
AC_MSG_CHECKING([for oci.h])
dnl Header directory for Instant Client SDK RPM install
OCISDKRPMINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/lib/oracle/\(.*\)/\('${PDO_OCI_CLIENT_DIR}'\)/lib[/]*$!\1/include/oracle/\2/\3!'`
dnl Header directory for manual installation
OCISDKMANINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/lib[/]*$!\1/include!'`
dnl Header directory for Instant Client SDK zip file install
OCISDKZIPINC=$PDO_OCI_LIB_DIR/sdk/include
if test -f "$OCISDKRPMINC/oci.h" ; then
PHP_ADD_INCLUDE($OCISDKRPMINC)
AC_MSG_RESULT($OCISDKRPMINC)
elif test -f "$OCISDKMANINC/oci.h" ; then
PHP_ADD_INCLUDE($OCISDKMANINC)
AC_MSG_RESULT($OCISDKMANINC)
elif test -f "$OCISDKZIPINC/oci.h" ; then
PHP_ADD_INCLUDE($OCISDKZIPINC)
AC_MSG_RESULT($OCISDKZIPINC)
else
AC_MSG_ERROR([I'm too dumb to figure out where the include dir is in your Instant Client install])
fi
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_LIB_DIR)
fi
case $PDO_OCI_VERSION in
7.3|8.0|8.1)
AC_MSG_ERROR([Oracle client libraries < 9 are not supported])
;;
esac
PHP_ADD_LIBRARY(clntsh, 1, PDO_OCI_SHARED_LIBADD)
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 Scrollable cursors?
PHP_CHECK_LIBRARY(clntsh, OCIStmtFetch2,
[
AC_DEFINE(HAVE_OCISTMTFETCH2,1,[ ])
], [], [
-L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
])
dnl Can handle bytes vs. characters?
PHP_CHECK_LIBRARY(clntsh, OCILobRead2,
[
AC_DEFINE(HAVE_OCILOBREAD2,1,[ ])
], [], [
-L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD
])
PHP_CHECK_PDO_INCLUDES
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)
PHP_ADD_EXTENSION_DEP(pdo_oci, pdo)
AC_DEFINE_UNQUOTED(PHP_PDO_OCI_CLIENT_VERSION, "$PDO_OCI_VERSION", [ ])
fi

45
config.w32 Normal file
View File

@@ -0,0 +1,45 @@
// 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');
}

895
oci_driver.c Normal file
View File

@@ -0,0 +1,895 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 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: |
| https://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> |
+----------------------------------------------------------------------+
*/
#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 void pdo_oci_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info) /* {{{ */
{
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);
}
}
/* }}} */
ub4 _oci_error(OCIError *err, pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *what, sword status, int isinit, const char *file, int line) /* {{{ */
{
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;
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 propagate 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 && status != OCI_SUCCESS_WITH_INFO) {
zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode, "SQLSTATE[%s]: %s", *pdo_err, einfo->errmsg);
}
return einfo->errcode;
}
/* }}} */
static void oci_handle_closer(pdo_dbh_t *dbh) /* {{{ */
{
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);
}
/* }}} */
static bool oci_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options) /* {{{ */
{
pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
pdo_oci_stmt *S = ecalloc(1, sizeof(*S));
ub4 prefetch;
zend_string *nsql = NULL;
int ret;
#ifdef HAVE_OCISTMTFETCH2
S->exec_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
PDO_CURSOR_FWDONLY) == 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, sql, &nsql);
if (ret == 1) {
/* query was re-written */
sql = nsql;
} else if (ret == -1) {
/* couldn't grok it */
strcpy(dbh->error_code, stmt->error_code);
efree(S);
return false;
}
/* 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 (ZSTR_LEN(sql) != 0) {
H->last_err = OCIStmtPrepare(S->stmt, H->err, (text*) ZSTR_VAL(sql), (ub4) ZSTR_LEN(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
if (nsql) {
zend_string_release(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 false;
}
}
prefetch = H->prefetch; /* Note 0 is allowed so in future REF CURSORs can be used & then passed with no row loss*/
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) {
zend_string_release(nsql);
nsql = NULL;
}
return true;
}
/* }}} */
static zend_long oci_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /* {{{ */
{
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*)ZSTR_VAL(sql), (ub4) ZSTR_LEN(sql), 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, 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);
sword last_err = H->last_err;
if (last_err) {
H->last_err = oci_drv_error("OCIStmtExecute");
}
if (!last_err || last_err == OCI_SUCCESS_WITH_INFO) {
/* 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 zend_string* oci_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype ) /* {{{ */
{
int qcount = 0;
char const *cu, *l, *r;
char *c, *quoted;
size_t quotedlen;
zend_string *quoted_str;
if (ZSTR_LEN(unquoted) == 0) {
return ZSTR_INIT_LITERAL("''", 0);
}
/* count single quotes */
for (cu = ZSTR_VAL(unquoted); (cu = strchr(cu,'\'')); qcount++, cu++)
; /* empty loop */
quotedlen = ZSTR_LEN(unquoted) + qcount + 2;
quoted = c = emalloc(quotedlen+1);
*c++ = '\'';
/* foreach (chunk that ends in a quote) */
for (l = ZSTR_VAL(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';
quoted_str = zend_string_init(quoted, quotedlen, 0);
efree(quoted);
return quoted_str;
}
/* }}} */
static bool oci_handle_begin(pdo_dbh_t *dbh) /* {{{ */
{
/* with Oracle, there is nothing special to be done */
return true;
}
/* }}} */
static bool oci_handle_commit(pdo_dbh_t *dbh) /* {{{ */
{
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 false;
}
return true;
}
/* }}} */
static bool oci_handle_rollback(pdo_dbh_t *dbh) /* {{{ */
{
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 false;
}
return true;
}
/* }}} */
static bool oci_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) /* {{{ */
{
zend_long lval;
pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
switch (attr) {
case PDO_ATTR_AUTOCOMMIT:
{
bool bval;
if (!pdo_get_bool_param(&bval, val)) {
return false;
}
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 false;
}
dbh->in_txn = false;
}
dbh->auto_commit = (unsigned int) bval;
return true;
}
case PDO_ATTR_PREFETCH:
{
if (!pdo_get_long_param(&lval, val)) {
return false;
}
H->prefetch = pdo_oci_sanitize_prefetch(lval);
return true;
}
case PDO_OCI_ATTR_ACTION:
{
#if (OCI_MAJOR_VERSION >= 10)
zend_string *action = zval_try_get_string(val);
if (UNEXPECTED(!action)) {
return false;
}
H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
(dvoid *) ZSTR_VAL(action), (ub4) ZSTR_LEN(action),
OCI_ATTR_ACTION, H->err);
if (H->last_err) {
oci_drv_error("OCIAttrSet: OCI_ATTR_ACTION");
return false;
}
return true;
#else
oci_drv_error("Unsupported attribute type");
return false;
#endif
}
case PDO_OCI_ATTR_CLIENT_INFO:
{
#if (OCI_MAJOR_VERSION >= 10)
zend_string *client_info = zval_try_get_string(val);
if (UNEXPECTED(!client_info)) {
return false;
}
H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
(dvoid *) ZSTR_VAL(client_info), (ub4) ZSTR_LEN(client_info),
OCI_ATTR_CLIENT_INFO, H->err);
if (H->last_err) {
oci_drv_error("OCIAttrSet: OCI_ATTR_CLIENT_INFO");
return false;
}
return true;
#else
oci_drv_error("Unsupported attribute type");
return false;
#endif
}
case PDO_OCI_ATTR_CLIENT_IDENTIFIER:
{
#if (OCI_MAJOR_VERSION >= 10)
zend_string *identifier = zval_try_get_string(val);
if (UNEXPECTED(!identifier)) {
return false;
}
H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
(dvoid *) ZSTR_VAL(identifier), (ub4) ZSTR_LEN(identifier),
OCI_ATTR_CLIENT_IDENTIFIER, H->err);
if (H->last_err) {
oci_drv_error("OCIAttrSet: OCI_ATTR_CLIENT_IDENTIFIER");
return false;
}
return true;
#else
oci_drv_error("Unsupported attribute type");
return false;
#endif
}
case PDO_OCI_ATTR_MODULE:
{
#if (OCI_MAJOR_VERSION >= 10)
zend_string *module = zval_try_get_string(val);
if (UNEXPECTED(!module)) {
return false;
}
H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
(dvoid *) ZSTR_VAL(module), (ub4) ZSTR_LEN(module),
OCI_ATTR_MODULE, H->err);
if (H->last_err) {
oci_drv_error("OCIAttrSet: OCI_ATTR_MODULE");
return false;
}
return true;
#else
oci_drv_error("Unsupported attribute type");
return false;
#endif
}
case PDO_OCI_ATTR_CALL_TIMEOUT:
{
#if (OCI_MAJOR_VERSION >= 18)
if (!pdo_get_long_param(&lval, val)) {
return false;
}
ub4 timeout = (ub4) lval;
H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX,
(dvoid *) &timeout, (ub4) 0,
OCI_ATTR_CALL_TIMEOUT, H->err);
if (H->last_err) {
oci_drv_error("OCIAttrSet: OCI_ATTR_CALL_TIMEOUT");
return false;
}
return true;
#else
oci_drv_error("Unsupported attribute type");
return false;
#endif
}
default:
return false;
}
}
/* }}} */
static int oci_handle_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value) /* {{{ */
{
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>>");
} else {
if (attr == PDO_ATTR_SERVER_INFO) {
ZVAL_STRING(return_value, (char *)infostr);
} 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);
}
}
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);
#elif defined(PHP_PDO_OCI_CLIENT_VERSION)
/* Compile time client version */
ZVAL_STRING(return_value, PHP_PDO_OCI_CLIENT_VERSION);
#else
return FALSE;
#endif /* Check for OCIClientVersion() support */
return TRUE;
}
case PDO_ATTR_AUTOCOMMIT:
ZVAL_BOOL(return_value, dbh->auto_commit);
return TRUE;
case PDO_ATTR_PREFETCH:
ZVAL_LONG(return_value, H->prefetch);
return TRUE;
case PDO_OCI_ATTR_CALL_TIMEOUT:
{
#if (OCI_MAJOR_VERSION >= 18)
ub4 timeout;
H->last_err = OCIAttrGet(H->svc, OCI_HTYPE_SVCCTX,
(dvoid *) &timeout, NULL,
OCI_ATTR_CALL_TIMEOUT, H->err);
if (H->last_err) {
oci_drv_error("OCIAttrGet: OCI_ATTR_CALL_TIMEOUT");
return FALSE;
}
ZVAL_LONG(return_value, (zend_long) timeout);
return TRUE;
#else
oci_drv_error("Unsupported attribute type");
return FALSE;
#endif
}
default:
return FALSE;
}
return FALSE;
}
/* }}} */
static zend_result pdo_oci_check_liveness(pdo_dbh_t *dbh) /* {{{ */
{
pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
sb4 error_code = 0;
#if (!((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))))
char version[256];
#endif
/* 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 const 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, /* last_id not supported */
pdo_oci_fetch_error_func,
oci_handle_get_attribute,
pdo_oci_check_liveness, /* check_liveness */
NULL, /* get_driver_methods */
NULL, /* request_shutdown */
NULL, /* in transaction, use PDO's internal tracking mechanism */
NULL /* get_gc */
};
static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
{
pdo_oci_db_handle *H;
int i, ret = 0;
struct pdo_data_src_parser vars[] = {
{ "charset", NULL, 0 },
{ "dbname", "", 0 },
{ "user", NULL, 0 },
{ "password", NULL, 0 }
};
php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 4);
H = pecalloc(1, sizeof(*H), dbh->is_persistent);
dbh->driver_data = H;
dbh->skip_param_evt =
1 << PDO_PARAM_EVT_FETCH_PRE |
1 << PDO_PARAM_EVT_FETCH_POST |
1 << PDO_PARAM_EVT_NORMALIZE;
H->prefetch = PDO_OCI_PREFETCH_DEFAULT;
/* allocate an environment */
#ifdef 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,
(sb4) 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 && vars[2].optval) {
dbh->username = pestrdup(vars[2].optval, dbh->is_persistent);
}
if (dbh->username) {
H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
dbh->username, (ub4) 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 && vars[3].optval) {
dbh->password = pestrdup(vars[3].optval, dbh->is_persistent);
}
if (dbh->password) {
H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
dbh->password, (ub4) 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");
/* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when
* user's password has expired, but is still usable.
*/
if (H->last_err != OCI_SUCCESS_WITH_INFO) {
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;
}
/* Get max character width */
H->last_err = OCINlsNumericInfoGet(H->env, H->err, &H->max_char_width, OCI_NLS_CHARSET_MAXBYTESZ);
if (H->last_err) {
oci_drv_error("OCINlsNumericInfoGet: OCI_NLS_CHARSET_MAXBYTESZ");
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);
}
return ret;
}
/* }}} */
const 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);
}
/* }}} */

1003
oci_statement.c Normal file

File diff suppressed because it is too large Load Diff

153
pdo_oci.c Normal file
View File

@@ -0,0 +1,153 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 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: |
| https://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> |
+----------------------------------------------------------------------+
*/
#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"
#ifdef ZTS
#include <TSRM/TSRM.h>
#endif
/* {{{ pdo_oci_module_entry */
static const zend_module_dep pdo_oci_deps[] = {
ZEND_MOD_REQUIRED("pdo")
ZEND_MOD_END
};
zend_module_entry pdo_oci_module_entry = {
STANDARD_MODULE_HEADER_EX, NULL,
pdo_oci_deps,
"PDO_OCI",
NULL,
PHP_MINIT(pdo_oci),
PHP_MSHUTDOWN(pdo_oci),
PHP_RINIT(pdo_oci),
NULL,
PHP_MINFO(pdo_oci),
PHP_PDO_OCI_VERSION,
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;
#ifdef ZTS
/* lock for pdo_oci_Env initialization */
static MUTEX_T pdo_oci_env_mutex;
#endif
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_oci)
{
REGISTER_PDO_CLASS_CONST_LONG("OCI_ATTR_ACTION", (zend_long)PDO_OCI_ATTR_ACTION);
REGISTER_PDO_CLASS_CONST_LONG("OCI_ATTR_CLIENT_INFO", (zend_long)PDO_OCI_ATTR_CLIENT_INFO);
REGISTER_PDO_CLASS_CONST_LONG("OCI_ATTR_CLIENT_IDENTIFIER", (zend_long)PDO_OCI_ATTR_CLIENT_IDENTIFIER);
REGISTER_PDO_CLASS_CONST_LONG("OCI_ATTR_MODULE", (zend_long)PDO_OCI_ATTR_MODULE);
REGISTER_PDO_CLASS_CONST_LONG("OCI_ATTR_CALL_TIMEOUT", (zend_long)PDO_OCI_ATTR_CALL_TIMEOUT);
if (FAILURE == php_pdo_register_driver(&pdo_oci_driver)) {
return FAILURE;
}
// Defer OCI init to PHP_RINIT_FUNCTION because with php-fpm,
// NLS_LANG is not yet available here.
#ifdef ZTS
pdo_oci_env_mutex = tsrm_mutex_alloc();
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(pdo_oci)
{
if (!pdo_oci_Env) {
#ifdef ZTS
tsrm_mutex_lock(pdo_oci_env_mutex);
if (!pdo_oci_Env) { // double-checked locking idiom
#endif
#ifdef 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
#ifdef ZTS
}
tsrm_mutex_unlock(pdo_oci_env_mutex);
#endif
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(pdo_oci)
{
php_pdo_unregister_driver(&pdo_oci_driver);
if (pdo_oci_Env) {
OCIHandleFree((dvoid*)pdo_oci_Env, OCI_HTYPE_ENV);
}
#ifdef ZTS
tsrm_mutex_free(pdo_oci_env_mutex);
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(pdo_oci)
{
php_info_print_table_start();
php_info_print_table_row(2, "PDO Driver for OCI 8 and later", "enabled");
php_info_print_table_end();
}
/* }}} */

36
php_pdo_oci.h Normal file
View File

@@ -0,0 +1,36 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 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: |
| https://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> |
+----------------------------------------------------------------------+
*/
#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
#include "php_version.h"
#define PHP_PDO_OCI_VERSION PHP_VERSION
#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 */

116
php_pdo_oci_int.h Normal file
View File

@@ -0,0 +1,116 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 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: |
| https://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> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_PDO_OCI_INT_H
#define PHP_PDO_OCI_INT_H
#include "zend_portability.h"
ZEND_DIAGNOSTIC_IGNORED_START("-Wstrict-prototypes")
#include <oci.h>
ZEND_DIAGNOSTIC_IGNORED_END
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 */
ub4 prefetch;
ub2 charset;
sword last_err;
sb4 max_char_width;
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 const 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);
#define oci_init_error(w) _oci_error(H->err, dbh, NULL, w, H->last_err, TRUE, __FILE__, __LINE__)
#define oci_drv_error(w) _oci_error(H->err, dbh, NULL, w, H->last_err, FALSE, __FILE__, __LINE__)
#define oci_stmt_error(w) _oci_error(S->err, stmt->dbh, stmt, w, S->last_err, FALSE, __FILE__, __LINE__)
extern const 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
enum {
PDO_OCI_ATTR_ACTION = PDO_ATTR_DRIVER_SPECIFIC,
PDO_OCI_ATTR_CLIENT_INFO,
PDO_OCI_ATTR_CLIENT_IDENTIFIER,
PDO_OCI_ATTR_MODULE,
PDO_OCI_ATTR_CALL_TIMEOUT
};
#endif /* PHP_PDO_OCI_INT_H */

22
tests/bug41996.phpt Normal file
View File

@@ -0,0 +1,22 @@
--TEST--
PDO OCI Bug #41996 (Problem accessing Oracle ROWID)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../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);
?>
--EXPECT--
bool(true)

28
tests/bug44301.phpt Normal file
View File

@@ -0,0 +1,28 @@
--TEST--
PDO OCI Bug #44301 (Segfault when an exception is thrown on persistent connections)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../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%epdo_oci%eoci_statement.c:%d)

70
tests/bug46274.phpt Normal file
View File

@@ -0,0 +1,70 @@
--TEST--
Bug #46274 (pdo_pgsql - Segfault when using PDO::ATTR_STRINGIFY_FETCHES and blob)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../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);
$db->beginTransaction();
$db->query('CREATE TABLE test46274 (id INT NOT NULL, blob1 BLOB)');
$stmt = $db->prepare("INSERT INTO test46274 (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 test46274");
// Resource
var_dump($res->fetch());
// Empty string
var_dump($res->fetch());
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test46274");
?>
--EXPECT--
array(2) {
["blob1"]=>
string(3) "foo"
[0]=>
string(3) "foo"
}
array(2) {
["blob1"]=>
string(0) ""
[0]=>
string(0) ""
}

77
tests/bug46274_2.phpt Normal file
View File

@@ -0,0 +1,77 @@
--TEST--
Bug #46274 (pdo_pgsql - Segfault when using PDO::ATTR_STRINGIFY_FETCHES and blob)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../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);
$db->beginTransaction();
$db->query('CREATE TABLE test46274_2 (id INT NOT NULL, blob1 BLOB)');
$stmt = $db->prepare("INSERT INTO test46274_2 (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 test46274_2");
// 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]);
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test46274_2");
?>
--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) ""

44
tests/bug54379.phpt Normal file
View File

@@ -0,0 +1,44 @@
--TEST--
Bug #54379 (PDO_OCI: UTF-8 output gets truncated)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../pdo/tests/pdo_test.inc';
if (!preg_match('/charset=.*utf8/i', getenv('PDOTEST_DSN')))
die('skip not UTF8 DSN');
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->exec("CREATE TABLE test54379 (col1 NVARCHAR2(20))");
$db->exec("INSERT INTO test54379 VALUES('12345678901234567890')");
$db->exec("INSERT INTO test54379 VALUES('あいうえおかきくけこさしすせそたちつてと')");
$stmt = $db->prepare("SELECT * FROM test54379");
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test54379");
?>
--EXPECT--
array(2) {
[0]=>
array(1) {
["col1"]=>
string(20) "12345678901234567890"
}
[1]=>
array(1) {
["col1"]=>
string(60) "あいうえおかきくけこさしすせそたちつてと"
}
}

184
tests/bug57702.phpt Normal file
View File

@@ -0,0 +1,184 @@
--TEST--
PDO OCI Bug #57702 (Multi-row BLOB fetches)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../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 = "create table test57702 (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 test57702 (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 test57702 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 test57702 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 test57702 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);
}
////////////////////
echo "\nFourth Query\n";
$a = array();
$i = 0;
foreach($db->query("select data1 as d4_1, data2 as d4_2 from test57702 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 test57702 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]));
}
////////////////////
echo "\nSixth Query\n";
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); // Let's use streams
$a = array();
$i = 0;
foreach($db->query("select data1 as d4_1, data2 as d4_2 from test57702 order by id") as $row) {
$a[$i][0] = $row['d4_1'];
$a[$i][1] = $row['d4_2'];
var_dump(stream_get_contents($a[$i][0]));
var_dump(stream_get_contents($a[$i][1]));
$i++;
}
print "done\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test57702");
?>
--EXPECT--
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"
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"
Sixth 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

140
tests/bug60994.phpt Normal file
View File

@@ -0,0 +1,140 @@
--TEST--
PDO OCI Bug #60994 (Reading a multibyte CLOB caps at 8192 characters)
--CREDITS--
Chuck Burgess
ashnazg@php.net
--EXTENSIONS--
mbstring
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../pdo/tests/pdo_test.inc';
if (!strpos(strtolower(getenv('PDOTEST_DSN')), 'charset=al32utf8')) die('skip expected output valid for AL32UTF8 character set');
PDOTest::skip();
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$dbh = PDOTest::factory();
$dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
$dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$dbh->exec('CREATE TABLE pdo_oci_bug60994 (id NUMBER, data CLOB, data2 NCLOB)');
$id = null;
$insert = $dbh->prepare('INSERT INTO pdo_oci_bug60994 (id, data, data2) VALUES (:id, :data, :data2)');
$insert->bindParam(':id', $id, \PDO::PARAM_STR);
$select = $dbh->prepare("SELECT data, data2 FROM pdo_oci_bug60994 WHERE id = :id");
echo PHP_EOL, 'Test 1: j', PHP_EOL;
$string1 = 'abc' . str_repeat('j', 8187) . 'xyz'; // 8193 chars total works fine here (even 1 million works fine, subject to memory_limit)
$id = 1;
$insert->bindParam(':data', $string1, \PDO::PARAM_STR, strlen($string1)); // length in bytes
$insert->bindParam(':data2', $string1, \PDO::PARAM_STR, strlen($string1));
$insert->execute();
$select->bindParam(':id', $id, \PDO::PARAM_STR);
$select->execute();
$row = $select->fetch();
$stream1 = stream_get_contents($row['DATA']);
$start1 = mb_substr($stream1, 0, 10);
$ending1 = mb_substr($stream1, -10);
echo 'size of string1 is ', strlen($string1), ' bytes, ', mb_strlen($string1), ' chars.', PHP_EOL;
echo 'size of stream1 is ', strlen($stream1), ' bytes, ', mb_strlen($stream1), ' chars.', PHP_EOL;
echo 'beg of stream1 is ', $start1, PHP_EOL;
echo 'end of stream1 is ', $ending1, PHP_EOL;
if ($string1 != $stream1 || $stream1 != stream_get_contents($row['DATA2'])) {
echo 'Expected nclob value to match clob value for stream1', PHP_EOL;
}
echo PHP_EOL, 'Test 2: £', PHP_EOL;
$string2 = 'abc' . str_repeat('£', 8187) . 'xyz'; // 8193 chars total is when it breaks
$id = 2;
$insert->bindParam(':data', $string2, \PDO::PARAM_STR, strlen($string2)); // length in bytes
$insert->bindParam(':data2', $string2, \PDO::PARAM_STR, strlen($string2));
$insert->execute();
$select->bindParam(':id', $id, \PDO::PARAM_STR);
$select->execute();
$row = $select->fetch();
$stream2 = stream_get_contents($row['DATA']);
$start2 = mb_substr($stream2, 0, 10);
$ending2 = mb_substr($stream2, -10);
echo 'size of string2 is ', strlen($string2), ' bytes, ', mb_strlen($string2), ' chars.', PHP_EOL;
echo 'size of stream2 is ', strlen($stream2), ' bytes, ', mb_strlen($stream2), ' chars.', PHP_EOL;
echo 'beg of stream2 is ', $start2, PHP_EOL;
echo 'end of stream2 is ', $ending2, PHP_EOL;
if ($string2 != $stream2 || $stream2 != stream_get_contents($row['DATA2'])) {
echo 'Expected nclob value to match clob value for stream2', PHP_EOL;
}
echo PHP_EOL, 'Test 3: Җ', PHP_EOL;
$string3 = 'abc' . str_repeat('Җ', 8187) . 'xyz'; // 8193 chars total is when it breaks
$id = 3;
$insert->bindParam(':data', $string3, \PDO::PARAM_STR, strlen($string3)); // length in bytes
$insert->bindParam(':data2', $string3, \PDO::PARAM_STR, strlen($string3));
$insert->execute();
$select->bindParam(':id', $id, \PDO::PARAM_STR);
$select->execute();
$row = $select->fetch();
$stream3 = stream_get_contents($row['DATA']);
$start3 = mb_substr($stream3, 0, 10);
$ending3 = mb_substr($stream3, -10);
echo 'size of string3 is ', strlen($string3), ' bytes, ', mb_strlen($string3), ' chars.', PHP_EOL;
echo 'size of stream3 is ', strlen($stream3), ' bytes, ', mb_strlen($stream3), ' chars.', PHP_EOL;
echo 'beg of stream3 is ', $start3, PHP_EOL;
echo 'end of stream3 is ', $ending3, PHP_EOL;
if ($string3 != $stream3 || $stream3 != stream_get_contents($row['DATA2'])) {
echo 'Expected nclob value to match clob value for stream3', PHP_EOL;
}
echo PHP_EOL, 'Test 4: の', PHP_EOL;
$string4 = 'abc' . str_repeat('の', 8187) . 'xyz'; // 8193 chars total is when it breaks
$id = 4;
$insert->bindParam(':data', $string4, \PDO::PARAM_STR, strlen($string4)); // length in bytes
$insert->bindParam(':data2', $string4, \PDO::PARAM_STR, strlen($string4));
$insert->execute();
$select->bindParam(':id', $id, \PDO::PARAM_STR);
$select->execute();
$row = $select->fetch();
$stream4 = stream_get_contents($row['DATA']);
$start4 = mb_substr($stream4, 0, 10);
$ending4 = mb_substr($stream4, -10);
echo 'size of string4 is ', strlen($string4), ' bytes, ', mb_strlen($string4), ' chars.', PHP_EOL;
echo 'size of stream4 is ', strlen($stream4), ' bytes, ', mb_strlen($stream4), ' chars.', PHP_EOL;
echo 'beg of stream4 is ', $start4, PHP_EOL;
echo 'end of stream4 is ', $ending4, PHP_EOL;
if ($string4 != $stream4 || $stream4 != stream_get_contents($row['DATA2'])) {
echo 'Expected nclob value to match clob value for stream4', PHP_EOL;
}
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "pdo_oci_bug60994");
?>
--EXPECT--
Test 1: j
size of string1 is 8193 bytes, 8193 chars.
size of stream1 is 8193 bytes, 8193 chars.
beg of stream1 is abcjjjjjjj
end of stream1 is jjjjjjjxyz
Test 2: £
size of string2 is 16380 bytes, 8193 chars.
size of stream2 is 16380 bytes, 8193 chars.
beg of stream2 is abc£££££££
end of stream2 is £££££££xyz
Test 3: Җ
size of string3 is 16380 bytes, 8193 chars.
size of stream3 is 16380 bytes, 8193 chars.
beg of stream3 is abcҖҖҖҖҖҖҖ
end of stream3 is ҖҖҖҖҖҖҖxyz
Test 4: の
size of string4 is 24567 bytes, 8193 chars.
size of stream4 is 24567 bytes, 8193 chars.
beg of stream4 is abcののののののの
end of stream4 is のののののののxyz

31
tests/bug_33707.phpt Normal file
View File

@@ -0,0 +1,31 @@
--TEST--
PDO OCI Bug #33707 (Errors in select statements not reported)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../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_does_not_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)"
}

58
tests/checkliveness.phpt Normal file
View File

@@ -0,0 +1,58 @@
--TEST--
PDO OCI checkliveness (code coverage)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require __DIR__.'/../../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');
$dsn = getenv('PDOTEST_DSN');
$user = getenv('PDOTEST_USER');
$pass = getenv('PDOTEST_PASS');
$attr = getenv('PDOTEST_ATTR');
try {
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
}
catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
// This triggers the call to check liveness
try {
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
}
catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
$db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
try {
$stmt = $db->prepare('SELECT * FROM dual');
$stmt->execute();
$row = $stmt->fetch();
var_dump($row);
} catch (PDOException $e) {
print $e->getMessage();
}
$db = null;
?>
--EXPECT--
array(2) {
["DUMMY"]=>
string(1) "X"
[0]=>
string(1) "X"
}

25
tests/common.phpt Normal file
View File

@@ -0,0 +1,25 @@
--TEST--
OCI
--EXTENSIONS--
pdo_oci
--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;

View File

@@ -0,0 +1,121 @@
--TEST--
Handling OCI_SUCCESS_WITH_INFO
--EXTENSIONS--
pdo
pdo_oci
--XFAIL--
This test frequently fails in CI
--SKIPIF--
<?php
if (getenv('SKIP_SLOW_TESTS')) die('skip slow tests excluded by request');
?>
--FILE--
<?php
function connectAsAdmin(): PDO {
return PDOTest::test_factory(__DIR__ . '/../../pdo_oci/tests/common.phpt');
}
function connectAsUser(string $username, string $password): PDO {
return new PDO(getenv('PDOTEST_DSN'), $username, $password);
}
function dropProfile(PDO $conn): void {
$conn->exec(<<<'SQL'
BEGIN
EXECUTE IMMEDIATE 'DROP PROFILE BUG77120_PROFILE CASCADE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2380 THEN
RAISE;
END IF;
END;
SQL
);
}
function dropUser(PDO $conn): void {
$conn->exec(<<<'SQL'
BEGIN
EXECUTE IMMEDIATE 'DROP USER BUG77120_USER CASCADE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -1918 THEN
RAISE;
END IF;
END;
SQL
);
}
function triggerCompilationError(PDO $conn): void {
$conn->exec(<<<'SQL'
CREATE OR REPLACE FUNCTION BUG77120(INT A) RETURN INT
AS
BEGIN
RETURN 0;
END;
SQL
);
}
require __DIR__ . '/../../pdo/tests/pdo_test.inc';
$conn = connectAsAdmin();
dropUser($conn);
dropProfile($conn);
$password = bin2hex(random_bytes(8));
$conn->exec('CREATE PROFILE BUG77120_PROFILE LIMIT PASSWORD_LIFE_TIME 1/86400 PASSWORD_GRACE_TIME 1');
$conn->exec('CREATE USER BUG77120_USER IDENTIFIED BY "' . $password . '" PROFILE BUG77120_PROFILE');
$conn->exec('GRANT CREATE SESSION TO BUG77120_USER');
// let the password expire
sleep(3); // 2 seconds is causing random test failures
$conn = connectAsUser('BUG77120_USER', $password);
var_dump($conn->errorInfo());
$conn = connectAsAdmin();
dropUser($conn);
dropProfile($conn);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
triggerCompilationError($conn);
var_dump($conn->errorInfo());
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
triggerCompilationError($conn);
var_dump($conn->errorInfo());
?>
--EXPECTF--
array(3) {
[0]=>
string(5) "HY000"
[1]=>
int(28002)
[2]=>
string(%d) "OCISessionBegin: OCI_SUCCESS_WITH_INFO: ORA-28002: %s
(%s:%d)"
}
array(3) {
[0]=>
string(5) "HY000"
[1]=>
int(24344)
[2]=>
string(%d) "OCIStmtExecute: OCI_SUCCESS_WITH_INFO: ORA-24344: %s
(%s:%d)"
}
array(3) {
[0]=>
string(5) "HY000"
[1]=>
int(24344)
[2]=>
string(%d) "OCIStmtExecute: OCI_SUCCESS_WITH_INFO: ORA-24344: %s
(%s:%d)"
}

View File

@@ -0,0 +1,57 @@
--TEST--
PDO_OCI: Attribute: Setting session action
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$query = 'select action from v$session where sid = sys_context(\'USERENV\', \'SID\')';
$dbh = PDOTest::factory();
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'ACTION NOT SET: ';
var_dump($row['action']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_ACTION, "some action"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'ACTION SET: ';
var_dump($row['action']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_ACTION, "something else!"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'ACTION RESET: ';
var_dump($row['action']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_ACTION, null));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'ACTION NULLED: ';
var_dump($row['action']);
echo "Done\n";
?>
--EXPECT--
ACTION NOT SET: NULL
bool(true)
ACTION SET: string(11) "some action"
bool(true)
ACTION RESET: string(15) "something else!"
bool(true)
ACTION NULLED: NULL
Done

View File

@@ -0,0 +1,68 @@
--TEST--
PDO_OCI: Attribute: Basic autocommit functionality
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$dbh = PDOTest::factory();
$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 test_pdo_oci_attr_autocommit_1 (col1 varchar2(20))");
$dbh->exec("insert into test_pdo_oci_attr_autocommit_1 (col1) values ('some data')");
$dbh2 = PDOTest::factory();
echo "Second connection should be able to see committed data\n";
$s = $dbh2->prepare("select col1 from test_pdo_oci_attr_autocommit_1");
$s->execute();
while ($r = $s->fetch()) {
echo "Data is: " . $r[0] . "\n";
}
echo "Done\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test_pdo_oci_attr_autocommit_1");
?>
--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

View File

@@ -0,0 +1,133 @@
--TEST--
PDO_OCI: Attribute: beginTransaction and native transactions
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$dbh = PDOTest::factory();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->exec("create table test_pdo_oci_attr_autocommit_2 (col1 varchar2(25))");
echo "Test 1 Check beginTransaction insertion\n";
$dbh->beginTransaction();
try {
$dbh->exec("insert into test_pdo_oci_attr_autocommit_2 (col1) values ('data 1')");
$dbh->exec("insert into test_pdo_oci_attr_autocommit_2 (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 test_pdo_oci_attr_autocommit_2 (col1) values ('not committed #1')");
$dbh->exec("insert into test_pdo_oci_attr_autocommit_2 (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 test_pdo_oci_attr_autocommit_2 (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 test_pdo_oci_attr_autocommit_2 (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 test_pdo_oci_attr_autocommit_2 (col1) values ('not committed #2')");
$dbh->exec("rollback");
$dbh->exec("insert into test_pdo_oci_attr_autocommit_2 (col1) values ('data 5')");
$dbh->exec("insert into test_pdo_oci_attr_autocommit_2 (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 test_pdo_oci_attr_autocommit_2");
$s->execute();
while ($r = $s->fetch()) {
echo $r[0] . "\n";
}
echo "Done\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test_pdo_oci_attr_autocommit_2");
?>
--EXPECTF--
Test 1 Check beginTransaction insertion
Test 2 Cause an exception and test beginTransaction rollback
Caught expected exception at line 33
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

View File

@@ -0,0 +1,54 @@
--TEST--
PDO_OCI: Attribute: closing a connection in non-autocommit mode commits data
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../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_EXCEPTION);
print "PDO::ATTR_AUTOCOMMIT: ";
var_dump($dbh->getAttribute(PDO::ATTR_AUTOCOMMIT));
echo "Insert data\n";
$dbh->exec("create table test_pdo_oci_attr_autocommit_3 (col1 varchar2(20))");
$dbh->exec("insert into test_pdo_oci_attr_autocommit_3 (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 test_pdo_oci_attr_autocommit_3");
$s->execute();
while ($r = $s->fetch()) {
echo "Data is: " . $r[0] . "\n";
}
echo "Done\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test_pdo_oci_attr_autocommit_3");
?>
--EXPECT--
PDO::ATTR_AUTOCOMMIT: bool(false)
Insert data
Second connection should be able to see committed data
Done

View File

@@ -0,0 +1,68 @@
--TEST--
PDO_OCI: Attribute: Setting and using call timeout
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
if (getenv('SKIP_SLOW_TESTS')) die('skip slow tests excluded by request');
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
if (strcasecmp(getenv('PDOTEST_USER'), "system") && strcasecmp(getenv('PDOTEST_USER'), "sys")) {
die("skip needs to be run as a user with access to DBMS_LOCK");
}
$dbh = PDOTest::factory();
preg_match('/^[[:digit:]]+/', $dbh->getAttribute(PDO::ATTR_CLIENT_VERSION), $matches);
if (!(isset($matches[0]) && $matches[0] >= 18)) {
die("skip works only with Oracle 18c or greater version of Oracle client libraries");
}
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
function mysleep($dbh, $t)
{
$stmt = $dbh->prepare("begin dbms_lock.sleep(:t); end;");
if (!$stmt) {
$error = $dbh->errorInfo();
echo "Prepare error was ", $error[2], "\n";
return;
}
$stmt->bindParam(":t", $t, PDO::PARAM_INT);
$r = $stmt->execute();
if ($r) {
echo "Execute succeeded\n";
} else {
$error = $dbh->errorInfo();
echo "Execute error was ", $error[2], "\n";
}
}
$dbh = PDOTest::factory();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
echo "Test 1\n";
$dbh->setAttribute(PDO::OCI_ATTR_CALL_TIMEOUT, 4000); // milliseconds
echo "call timeout:\n";
var_dump($dbh->getAttribute(PDO::OCI_ATTR_CALL_TIMEOUT));
$r = mysleep($dbh, 8); // seconds
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
Test 1
call timeout:
int(4000)
Execute error was OCIStmtExecute: ORA-%r(03136|03156)%r: %s
(%s:%d)
===DONE===

View File

@@ -0,0 +1,83 @@
--TEST--
PDO_OCI: Attribute: Column Case
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../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

View File

@@ -0,0 +1,45 @@
--TEST--
PDO_OCI: Attribute: Client version
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../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 (count($s) > 1 && (($s[0] == 10 && $s[1] >= 2) || $s[0] >= 11)) {
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

View File

@@ -0,0 +1,57 @@
--TEST--
PDO_OCI: Attribute: Setting session client identifier
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$query = 'select client_identifier from v$session where sid = sys_context(\'USERENV\', \'SID\')';
$dbh = PDOTest::factory();
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_IDENTIFIER NOT SET: ';
var_dump($row['client_identifier']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_CLIENT_IDENTIFIER, "some client identifier"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_IDENTIFIER SET: ';
var_dump($row['client_identifier']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_CLIENT_IDENTIFIER, "something else!"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_IDENTIFIER RESET: ';
var_dump($row['client_identifier']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_CLIENT_IDENTIFIER, null));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_IDENTIFIER NULLED: ';
var_dump($row['client_identifier']);
echo "Done\n";
?>
--EXPECT--
CLIENT_IDENTIFIER NOT SET: NULL
bool(true)
CLIENT_IDENTIFIER SET: string(22) "some client identifier"
bool(true)
CLIENT_IDENTIFIER RESET: string(15) "something else!"
bool(true)
CLIENT_IDENTIFIER NULLED: NULL
Done

View File

@@ -0,0 +1,57 @@
--TEST--
PDO_OCI: Attribute: Setting session client info
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$query = 'select client_info from v$session where sid = sys_context(\'USERENV\', \'SID\')';
$dbh = PDOTest::factory();
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_INFO NOT SET: ';
var_dump($row['client_info']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_CLIENT_INFO, "some client info"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_INFO SET: ';
var_dump($row['client_info']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_CLIENT_INFO, "something else!"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_INFO RESET: ';
var_dump($row['client_info']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_CLIENT_INFO, null));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'CLIENT_INFO NULLED: ';
var_dump($row['client_info']);
echo "Done\n";
?>
--EXPECT--
CLIENT_INFO NOT SET: NULL
bool(true)
CLIENT_INFO SET: string(16) "some client info"
bool(true)
CLIENT_INFO RESET: string(15) "something else!"
bool(true)
CLIENT_INFO NULLED: NULL
Done

View File

@@ -0,0 +1,23 @@
--TEST--
PDO_OCI: Attribute: verify driver name
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require __DIR__ . '/../../pdo/tests/pdo_test.inc';
$dbh = PDOTest::factory();
var_dump($dbh->getAttribute(PDO::ATTR_DRIVER_NAME));
echo "Done\n";
?>
--EXPECT--
string(3) "oci"
Done

View File

@@ -0,0 +1,51 @@
--TEST--
PDO_OCI: Attribute: Setting session module
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$query = 'select module from v$session where sid = sys_context(\'USERENV\', \'SID\')';
$dbh = PDOTest::factory();
var_dump($dbh->setAttribute(PDO::OCI_ATTR_MODULE, "some module"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'MODULE SET: ';
var_dump($row['module']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_MODULE, "something else!"));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'MODULE RESET: ';
var_dump($row['module']);
var_dump($dbh->setAttribute(PDO::OCI_ATTR_MODULE, null));
$stmt = $dbh->query($query);
$row = $stmt->fetch();
echo 'MODULE NULLED: ';
var_dump($row['module']);
echo "Done\n";
?>
--EXPECT--
bool(true)
MODULE SET: string(11) "some module"
bool(true)
MODULE RESET: string(15) "something else!"
bool(true)
MODULE NULLED: NULL
Done

View File

@@ -0,0 +1,63 @@
--TEST--
PDO_OCI: Attribute: Oracle Nulls
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../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

View File

@@ -0,0 +1,80 @@
--TEST--
PDO_OCI: Attribute: Set prefetch on connection
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$dbh = PDOTest::factory();
echo "Test connect\n";
putenv('PDOTEST_ATTR='.serialize(array(PDO::ATTR_PREFETCH=>101)));
$dbh = PDOTest::factory();
echo $dbh->getAttribute(PDO::ATTR_PREFETCH), "\n";
// Verify can fetch
$s = $dbh->prepare("select dummy from dual" );
$s->execute();
while ($r = $s->fetch()) {
echo $r[0] . "\n";
}
echo "Test set 102\n";
$dbh->setAttribute(PDO::ATTR_PREFETCH, 102);
echo $dbh->getAttribute(PDO::ATTR_PREFETCH), "\n";
// Verify can fetch
$s = $dbh->prepare("select dummy from dual" );
$s->execute();
while ($r = $s->fetch()) {
echo $r[0] . "\n";
}
echo "Test set -1: (Uses 0)\n";
$dbh->setAttribute(PDO::ATTR_PREFETCH, -1);
echo $dbh->getAttribute(PDO::ATTR_PREFETCH), "\n";
// Verify can fetch
$s = $dbh->prepare("select dummy from dual" );
$s->execute();
while ($r = $s->fetch()) {
echo $r[0] . "\n";
}
echo "Test set PHP_INT_MAX: (Uses default)\n";
$dbh->setAttribute(PDO::ATTR_PREFETCH, PHP_INT_MAX);
echo $dbh->getAttribute(PDO::ATTR_PREFETCH), "\n";
// 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
101
X
Test set 102
102
X
Test set -1: (Uses 0)
0
X
Test set PHP_INT_MAX: (Uses default)
100
X
Done

View File

@@ -0,0 +1,49 @@
--TEST--
PDO_OCI: Attribute: prefetch on statements
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../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

View File

@@ -0,0 +1,42 @@
--TEST--
PDO_OCI: Attribute: Server version and info
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../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

View File

@@ -0,0 +1,68 @@
--TEST--
PDO OCI specific class constants
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$expected = [
'OCI_ATTR_CLIENT_INFO' => true,
'OCI_ATTR_ACTION' => true,
'OCI_ATTR_CLIENT_IDENTIFIER' => true,
'OCI_ATTR_MODULE' => true,
'OCI_ATTR_CALL_TIMEOUT' => true,
];
$ref = new ReflectionClass('PDO');
$constants = $ref->getConstants();
$values = [];
foreach ($constants as $name => $value) {
if (substr($name, 0, 8) == 'OCI_ATTR') {
if (!isset($values[$value])) {
$values[$value] = [$name];
} else {
$values[$value][] = $name;
}
if (isset($expected[$name])) {
unset($expected[$name]);
unset($constants[$name]);
}
} else {
unset($constants[$name]);
}
}
if (!empty($constants)) {
printf("[001] Dumping list of unexpected constants\n");
var_dump($constants);
}
if (!empty($expected)) {
printf("[002] Dumping list of missing constants\n");
var_dump($expected);
}
if (!empty($values)) {
foreach ($values as $value => $constants) {
if (count($constants) > 1) {
printf("[003] Several constants share the same value '%s'\n", $value);
var_dump($constants);
}
}
}
print "done!";
?>
--EXPECT--
done!

View File

@@ -0,0 +1,39 @@
--TEST--
PDO_OCI: Bug #69356 (PDOStatement::debugDumpParams() truncates query)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$db = PDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$stmt = $db->query("
SELECT '
Dumps the information contained by a prepared statement directly on the output. It will provide the SQL query in use, the number of parameters used (Params), the list of parameters, with their name, type (paramtype) as an integer, their key name or position, and the position in the query (if this is supported by the PDO driver, otherwise, it will be -1).
This is a debug function, which dump directly the data on the normal output.
Tip:
As with anything that outputs its result directly to the browser, the output-control functions can be used to capture the output of this function, and save it in a string (for example).
This will only dumps the parameters in the statement at the moment of the dump. Extra parameters are not stored in the statement, and not displayed.
' FROM DUAL
");
var_dump($stmt->debugDumpParams());
?>
--EXPECT--
SQL: [844]
SELECT '
Dumps the information contained by a prepared statement directly on the output. It will provide the SQL query in use, the number of parameters used (Params), the list of parameters, with their name, type (paramtype) as an integer, their key name or position, and the position in the query (if this is supported by the PDO driver, otherwise, it will be -1).
This is a debug function, which dump directly the data on the normal output.
Tip:
As with anything that outputs its result directly to the browser, the output-control functions can be used to capture the output of this function, and save it in a string (for example).
This will only dumps the parameters in the statement at the moment of the dump. Extra parameters are not stored in the statement, and not displayed.
' FROM DUAL
Params: 0
NULL

View File

@@ -0,0 +1,56 @@
--TEST--
PDO_OCI: check fread() EOF
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../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(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$dbh = PDOTest::factory();
$dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
// Initialization
$stmtarray = array(
"create table test_oci_fread_1 (id number, data clob)",
"declare
lob1 clob := 'abc' || lpad('j',4020,'j') || 'xyz';
begin
insert into test_oci_fread_1 (id,data) values (1, lob1);
end;"
);
foreach ($stmtarray as $stmt) {
$dbh->exec($stmt);
}
echo "Test 1\n";
$s = $dbh->query("select data from test_oci_fread_1 where id = 1");
$r = $s->fetch();
$sh = $r['data'];
while (!feof($sh)) {
$buffer = fread($sh,1024);
echo '*'.$buffer.'*';
}
echo "\n";
fclose($sh);
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, test_oci_fread_1");
?>
--EXPECT--
Test 1
*abcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj**jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj**jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj**jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjxyz*

View File

@@ -0,0 +1,29 @@
--TEST--
PDO_OCI: phpinfo() output
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
$db = PDOTest::factory();
ob_start();
phpinfo();
$tmp = ob_get_contents();
ob_end_clean();
$reg = 'PDO Driver for OCI 8 and later => enabled';
if (!preg_match("/$reg/", $tmp)) {
printf("[001] Cannot find OCI PDO driver line in phpinfo() output\n");
}
print "done!";
?>
--EXPECT--
done!

158
tests/pdo_oci_quote1.phpt Normal file
View File

@@ -0,0 +1,158 @@
--TEST--
Test PDO->quote() for PDO_OCI
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require __DIR__ . '/../../pdo/tests/pdo_test.inc';
$db = PDOTest::factory();
$db->query("create table test_pdo_oci_quote1 (t varchar2(100))");
$stmt = $db->prepare('select * from test_pdo_oci_quote1');
// The intent is that the fetched data be identical to the unquoted string.
// Remember!: use bind variables instead of PDO->quote()
$a = array("", "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 test_pdo_oci_quote1");
$db->query("insert into test_pdo_oci_quote1 (t) values($q)");
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
}
echo "Done\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test_pdo_oci_quote1");
?>
--EXPECT--
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

View File

@@ -0,0 +1,320 @@
--TEST--
PDO_OCI: PDOStatement->getColumnMeta
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
echo "Preparations before the test\n";
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
try {
$db = PDOTest::factory();
$db->exec("CREATE TABLE test_pdo_oci_stmt_getcolumnmeta(id INT)");
$db->beginTransaction();
$stmt = $db->prepare('SELECT id FROM test_pdo_oci_stmt_getcolumnmeta ORDER BY id ASC');
echo "Test 1. calling function with invalid parameters\n";
// execute() has not been called yet
// NOTE: no warning
$tmp = $stmt->getColumnMeta(0);
printf(" 1.1 Expecting false got %s\n", var_export($tmp, true));
echo(" 1.2 ");
$stmt->execute();
// PDOStatement::getColumnMeta() expects exactly 1 argument, 0 given in
try {
$tmp = $stmt->getColumnMeta();
} catch (ArgumentCountError $e) {
if (false !== $tmp) {
printf("[1.2] Expecting false got %s\n", var_export($tmp, true));
}
echo $e->getMessage(), "\n";
}
// invalid offset
echo " 1.3 ";
try {
$tmp = $stmt->getColumnMeta(-1);
} catch (ValueError $e) {
if (false !== $tmp) {
printf("[1.3] Expecting false got %s\n", var_export($tmp, true));
}
echo $e->getMessage(), "\n";
}
// PDOStatement::getColumnMeta(): Argument #1 must be of type int, array given in
echo " 1.4 ";
try {
$tmp = $stmt->getColumnMeta(array());
} catch (TypeError $e) {
if (false !== $tmp)
printf("[1.4] Expecting false got %s\n", var_export($tmp, true));
echo $e->getMessage(), "\n";
}
// PDOStatement::getColumnMeta() expects exactly 1 argument, 2 given in
echo " 1.5 ";
try {
$tmp = $stmt->getColumnMeta(1, 1);
} catch (ArgumentCountError $e) {
if (false !== $tmp)
printf("[1.5] Expecting false got %s\n", var_export($tmp, true));
echo $e->getMessage(), "\n";
}
// invalid offset
$tmp = $stmt->getColumnMeta(1);
printf(" 1.6 Expecting false because of invalid offset got %s\n", var_export($tmp, true));
echo "Test 2. testing return values\n";
echo "Test 2.1 testing array returned\n";
$stmt = $db->prepare('SELECT id FROM test_pdo_oci_stmt_getcolumnmeta ORDER BY id ASC');
$stmt->execute();
$native = $stmt->getColumnMeta(0);
if (count($native) == 0) {
printf("[008] Meta data seems wrong, %s / %s\n",
var_export($native, true), var_export($emulated, true));
}
function test_return($meta, $offset, $native_type, $pdo_type){
if (empty($meta)) {
printf("[%03d + 2] getColumnMeta() failed, %d - %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
return false;
}
$elements = array('flags', 'scale', 'name', 'len', 'precision', 'pdo_type');
foreach ($elements as $k => $element)
if (!isset($meta[$element])) {
printf("[%03d + 3] Element %s missing, %s\n", $offset,
$element, var_export($meta, true));
return false;
}
if (!is_null($native_type)) {
if (!isset($meta['native_type'])) {
printf("[%03d + 4] Element native_type missing, %s\n", $offset,
var_export($meta, true));
return false;
}
if (!is_array($native_type))
$native_type = array($native_type);
$found = false;
foreach ($native_type as $k => $type) {
if ($meta['native_type'] == $type) {
$found = true;
break;
}
}
if (!$found) {
printf("[%03d + 5] Expecting native type %s, %s\n", $offset,
var_export($native_type, true), var_export($meta, true));
return false;
}
}
if (!is_null($pdo_type) && ($meta['pdo_type'] != $pdo_type)) {
printf("[%03d + 6] Expecting PDO type %s got %s (%s)\n", $offset,
$pdo_type, var_export($meta, true), var_export($meta['native_type']));
return false;
}
return true;
}
function test_meta(&$db, $offset, $sql_type, $value, $native_type, $pdo_type) {
$db->exec(<<<SQL
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE test_pdo_oci_stmt_getcolumnmeta';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
SQL
);
$sql = sprintf('CREATE TABLE test_pdo_oci_stmt_getcolumnmeta(id INT, label %s)', $sql_type);
$stmt = $db->prepare($sql);
$stmt->execute();
if (!$db->exec(sprintf("INSERT INTO test_pdo_oci_stmt_getcolumnmeta(id, label) VALUES (1, '%s')", $value))) {
printf("[%03d] + 1] Insert failed, %d - %s\n", $offset,
$db->errorCode(), var_export($db->errorInfo(), true));
return false;
}
$stmt = $db->prepare('SELECT id, label FROM test_pdo_oci_stmt_getcolumnmeta');
$stmt->execute();
$meta = $stmt->getColumnMeta(1);
return test_return($meta, $offset, $native_type, $pdo_type);
}
echo "Test 2.2 testing numeric columns\n";
test_meta($db, 20, 'NUMBER' , 0 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 30, 'NUMBER' , 256 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 40, 'INT' , 256 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 50, 'INTEGER' , 256 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 60, 'NUMBER' , 256.01 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 70, 'NUMBER' , -8388608 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 80, 'NUMBER' , 2147483648 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 90, 'NUMBER' , 4294967295 , 'NUMBER', PDO::PARAM_STR);
test_meta($db, 100, 'DEC' , 1.01 , 'NUMBER' , PDO::PARAM_STR);
test_meta($db, 110, 'DECIMAL' , 1.01 , 'NUMBER' , PDO::PARAM_STR);
test_meta($db, 120, 'FLOAT' , 1.01 , 'FLOAT' , PDO::PARAM_STR);
test_meta($db, 130, 'DOUBLE PRECISION', 1.01 , 'FLOAT' , PDO::PARAM_STR);
test_meta($db, 140, 'BINARY_FLOAT' , 1.01 , 'BINARY_FLOAT' , PDO::PARAM_STR);
test_meta($db, 150, 'BINARY_DOUBLE' , 1.01 , 'BINARY_DOUBLE', PDO::PARAM_STR);
echo "Test 2.3 testing temporal columns\n";
$db->exec("alter session set nls_date_format='YYYY-MM-DD'");
test_meta($db, 160, 'DATE' , '2008-04-23' , 'DATE', PDO::PARAM_STR);
echo "Test 2.4 testing string columns\n";
test_meta($db, 170, 'CHAR(1)' , 'a' , 'CHAR' , PDO::PARAM_STR);
test_meta($db, 180, 'CHAR(10)' , '0123456789' , 'CHAR' , PDO::PARAM_STR);
test_meta($db, 190, 'CHAR(255)' , str_repeat('z', 255) , 'CHAR' , PDO::PARAM_STR);
test_meta($db, 200, 'VARCHAR(1)' , 'a' , 'VARCHAR2' , PDO::PARAM_STR);
test_meta($db, 210, 'VARCHAR(10)' , '0123456789' , 'VARCHAR2' , PDO::PARAM_STR);
test_meta($db, 220, 'VARCHAR(255)' , str_repeat('z', 255) , 'VARCHAR2' , PDO::PARAM_STR);
test_meta($db, 230, 'VARCHAR2(1)' , 'a' , 'VARCHAR2' , PDO::PARAM_STR);
test_meta($db, 240, 'VARCHAR2(10)' , '0123456789' , 'VARCHAR2' , PDO::PARAM_STR);
test_meta($db, 250, 'VARCHAR2(255)' , str_repeat('z', 255) , 'VARCHAR2' , PDO::PARAM_STR);
test_meta($db, 260, 'NCHAR(1)' , 'a' , 'NCHAR' , PDO::PARAM_STR);
test_meta($db, 270, 'NCHAR(10)' , '0123456789' , 'NCHAR' , PDO::PARAM_STR);
test_meta($db, 280, 'NCHAR(255)' , str_repeat('z', 255) , 'NCHAR' , PDO::PARAM_STR);
test_meta($db, 290, 'NVARCHAR2(1)' , 'a' , 'NVARCHAR2', PDO::PARAM_STR);
test_meta($db, 300, 'NVARCHAR2(10)' , '0123456789' , 'NVARCHAR2', PDO::PARAM_STR);
test_meta($db, 310, 'NVARCHAR2(255)', str_repeat('z', 255) , 'NVARCHAR2', PDO::PARAM_STR);
echo "Test 2.5 testing lobs columns\n";
test_meta($db, 320, 'CLOB' , str_repeat('b', 255) , 'CLOB' , PDO::PARAM_LOB);
test_meta($db, 330, 'BLOB' , str_repeat('b', 256) , 'BLOB' , PDO::PARAM_LOB);
test_meta($db, 340, 'NCLOB' , str_repeat('b', 255) , 'NCLOB' , PDO::PARAM_LOB);
test_meta($db, 350, 'LONG' , str_repeat('b', 256) , 'LONG' , PDO::PARAM_STR);
test_meta($db, 360, 'LONG RAW' , str_repeat('b', 256) , 'LONG RAW', PDO::PARAM_STR);
test_meta($db, 370, 'RAW(256)' , str_repeat('b', 256) , 'RAW' , PDO::PARAM_STR);
$db->exec(<<<SQL
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE test_pdo_oci_stmt_getcolumnmeta';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
SQL
);
echo "Test 2.6 testing function return\n";
$stmt = $db->query('SELECT count(*) FROM dual');
$meta = $stmt->getColumnMeta(0);
test_return($meta, 380, 'NUMBER', PDO::PARAM_STR);
$stmt = $db->query("SELECT TO_DATE('2008-04-23') FROM dual");
$meta = $stmt->getColumnMeta(0);
test_return($meta, 390, 'DATE', PDO::PARAM_STR);
$stmt = $db->query("SELECT TO_CHAR(542) FROM dual");
$meta = $stmt->getColumnMeta(0);
test_return($meta, 400, 'VARCHAR2', PDO::PARAM_STR);
echo "Test 2.7 testing flags returned\n";
$sql = sprintf('CREATE TABLE test_pdo_oci_stmt_getcolumnmeta(id INT NOT NULL, label INT NULL)');
$stmt = $db->prepare($sql);
$stmt->execute();
$db->exec('INSERT INTO test_pdo_oci_stmt_getcolumnmeta(id, label) VALUES (1, 1)');
$stmt = $db->query('SELECT id, label FROM test_pdo_oci_stmt_getcolumnmeta');
$meta = $stmt->getColumnMeta(0);
// verify the flags array contains a not_null flag and not nullable flags
if (!isset($meta['flags'])) {
printf("[1001] No flags contained in metadata %s\n", var_export($meta, true));
} else {
$flags = $meta['flags'];
$found = false;
foreach ($flags as $k => $flag) {
if ($flag == 'not_null')
$found = true;
if ($flag == 'nullable')
printf("[1003] Flags seem wrong %s\n", var_export($meta, true));
}
if (!$found)
printf("[1002] Flags seem wrong %s\n", var_export($meta, true));
}
$meta = $stmt->getColumnMeta(1);
// verify the flags array contains a nullable flag and not not_null flags
if (!isset($meta['flags'])) {
printf("[1003] No flags contained in metadata %s\n", var_export($meta, true));
} else {
$flags = $meta['flags'];
$found = false;
foreach ($flags as $k => $flag) {
if ($flag == 'not_null')
printf("[1004] Flags seem wrong %s\n", var_export($meta, true));
if ($flag == 'nullable')
$found = true;
}
if (!$found)
printf("[1005] Flags seem wrong %s\n", var_export($meta, true));
}
} catch (PDOException $e) {
// we should never get here, we use warnings, but never trust a system...
printf("[001] %s, [%s} %s\n",
$e->getMessage(), $db->errorInfo(), implode(' ', $db->errorInfo()));
}
print "done!";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test_pdo_oci_stmt_getcolumnmeta");
?>
--EXPECT--
Preparations before the test
Test 1. calling function with invalid parameters
1.1 Expecting false got false
1.2 PDOStatement::getColumnMeta() expects exactly 1 argument, 0 given
1.3 PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0
1.4 PDOStatement::getColumnMeta(): Argument #1 ($column) must be of type int, array given
1.5 PDOStatement::getColumnMeta() expects exactly 1 argument, 2 given
1.6 Expecting false because of invalid offset got false
Test 2. testing return values
Test 2.1 testing array returned
Test 2.2 testing numeric columns
Test 2.3 testing temporal columns
Test 2.4 testing string columns
Test 2.5 testing lobs columns
Test 2.6 testing function return
Test 2.7 testing flags returned
done!

108
tests/pdo_oci_stream_1.phpt Normal file
View File

@@ -0,0 +1,108 @@
--TEST--
PDO_OCI: stream_get_contents length & offset test
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../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(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$dbh = PDOTest::factory();
$dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
// Initialization
$stmtarray = array(
"create table test_pdo_oci_stream_1 (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 test_pdo_oci_stream_1 (id,data) values (1, 'abcdefghijklmnopqrstuvwxyz');
insert into test_pdo_oci_stream_1 (id,data) values (2, lob1);
end;");
echo "Test 1\n";
$s = $dbh->prepare("select data from test_pdo_oci_stream_1 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 test_pdo_oci_stream_1 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--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, test_pdo_oci_stream_1");
?>
--EXPECT--
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

122
tests/pdo_oci_stream_2.phpt Normal file
View File

@@ -0,0 +1,122 @@
--TEST--
PDO OCI: Insert and fetch 1K records from a table that contains 1 number and 2 LOB columns (stress test)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
if (getenv('SKIP_SLOW_TESTS')) die('skip slow tests excluded by request');
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require(__DIR__ . '/../../pdo/tests/pdo_test.inc');
$db = PDOTest::factory();
$query = "create table test_pdo_oci_stream_2 (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 test_pdo_oci_stream_2 (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();
}
$a1 = str_repeat('a', 4086);
$a2 = str_repeat('b', 4087);
$a3 = str_repeat('c', 4088);
$a4 = str_repeat('d', 4089);
$a5 = str_repeat('e', 4090);
$a6 = str_repeat('f', 4091);
$a7 = str_repeat('g', 4092);
$a8 = str_repeat('h', 4093);
$a9 = str_repeat('i', 4094);
$a10 = str_repeat('j', 4095);
printf("Inserting 1000 Records ... ");
for($i=0; $i<100; $i++) {
do_insert($db, $i * 10 + 1, $a1, $a10);
do_insert($db, $i * 10 + 2, $a2, $a9);
do_insert($db, $i * 10 + 3, $a3, $a8);
do_insert($db, $i * 10 + 4, $a4, $a7);
do_insert($db, $i * 10 + 5, $a5, $a6);
do_insert($db, $i * 10 + 6, $a6, $a5);
do_insert($db, $i * 10 + 7, $a7, $a4);
do_insert($db, $i * 10 + 8, $a8, $a3);
do_insert($db, $i * 10 + 9, $a9, $a2);
do_insert($db, $i * 10 + 10, $a10, $a1);
}
printf("Done\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
$i = 0;
$j = 9;
$a_val = ord('a');
foreach($db->query("select data1 as d4_1, data2 as d4_2 from test_pdo_oci_stream_2 order by id") as $row) {
$a = $row['d4_1'];
$a1 = $row['d4_2'];
$str1 = stream_get_contents($a);
$str2 = stream_get_contents($a1);
$str1len = strlen($str1);
$str2len = strlen($str2);
$b = ord($str1[0]);
$b1 = ord($str2[0]);
if (($b != ($a_val + $i)) && ($str1len != (4086 + $i)) &&
($b1 != ($a_val + $j)) && ($str2len != (4086 + $j))) {
printf("There is a bug!\n");
printf("Col1:\n");
printf("a_val = %d\n", $a_val);
printf("b = %d\n", $b);
printf("i = %d\n", $i);
printf("str1len = %d\n", $str1len);
printf("Col2:\n");
printf("a_val = %d\n", $a_val);
printf("b1 = %d\n", $b1);
printf("j = %d\n", $j);
printf("str2len = %d\n", $str1len);
}
$i++;
if ($i>9)
$i = 0;
$j--;
if ($j<0)
$j = 9;
}
echo "Fetch operation done!\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test_pdo_oci_stream_2");
?>
--EXPECT--
Inserting 1000 Records ... Done
Fetch operation done!

View File

@@ -0,0 +1,86 @@
--TEST--
PDO OCI: Test to verify all implicitly created temporary LOB are cleaned up
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../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');
$clobquery1 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery2 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery3 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery4 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery5 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery6 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery7 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery8 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery9 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$clobquery10 = "select TO_CLOB('Hello World') CLOB_DATA from dual";
$stmt= $db->prepare($clobquery1);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery2);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery3);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery4);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery5);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery6);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery7);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery8);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery9);
$stmt->execute();
$row = $stmt->fetch();
$stmt= $db->prepare($clobquery10);
$stmt->execute();
$row = $stmt->fetch();
$query1 = "SELECT SYS_CONTEXT('USERENV', 'SID') SID FROM DUAL";
$stmt1 = $db->prepare($query1);
$stmt1->execute();
$row1 = $stmt1->fetch();
$sid_value = $row1[0];
$query2 = "SELECT (CACHE_LOBS+NOCACHE_LOBS+ABSTRACT_LOBS) FROM V\$TEMPORARY_LOBS WHERE SID = :SID_VALUE";
$stmt2 = $db->prepare($query2);
$stmt2->bindParam(':SID_VALUE', $sid_value);
$stmt2->execute();
$row2 = $stmt2->fetch();
/* 1 temporary LOB still exists in V$TEMPORARY_LOBS since the destructor of $stmt is not yet called by PHP */
if ($row2[0] > 1)
{
echo "TEMP_LOB is not yet cleared!" . $row2[0] . "\n";
}
else
{
echo "Success! All the temporary LOB in previously closed statements are properly cleaned.\n";
}
?>
--EXPECT--
Success! All the temporary LOB in previously closed statements are properly cleaned.

30
tests/pecl_bug_11345.phpt Normal file
View File

@@ -0,0 +1,30 @@
--TEST--
PECL PDO_OCI Bug #11345 (Test invalid character set name)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
require(__DIR__.'/../../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)

73
tests/pecl_bug_6364.phpt Normal file
View File

@@ -0,0 +1,73 @@
--TEST--
PECL PDO_OCI Bug #6364 (segmentation fault on stored procedure call with OUT binds)
--EXTENSIONS--
pdo
pdo_oci
--SKIPIF--
<?php
if (getenv('SKIP_ASAN')) die('xleak leaks memory under asan');
require(__DIR__.'/../../pdo/tests/pdo_test.inc');
PDOTest::skip();
?>
--FILE--
<?php
require __DIR__ . '/../../pdo/tests/pdo_test.inc';
$dbh = PDOTest::factory();
$dbh->exec ("create table test6364 (c1 varchar2(10), c2 varchar2(10), c3 varchar2(10), c4 varchar2(10), c5 varchar2(10))");
$dbh->exec ("create procedure test6364_sp(p1 IN varchar2, p2 IN varchar2, p3 IN varchar2, p4 OUT varchar2, p5 OUT varchar2) as begin insert into test6364 (c1, c2, c3) values (p1, p2, p3); p4 := 'val4'; p5 := 'val5'; end;");
$stmt = $dbh->prepare("call test6364_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 test6364") as $row) {
var_dump($row);
}
print "Done\n";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_oci/tests/common.phpt');
PDOTest::dropTableIfExists($db, "test6364");
$db->exec("DROP PROCEDURE test6364_sp");
?>
--EXPECT--
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