From f67a9bdc52c39eed6837aef8a1eca195549b1469 Mon Sep 17 00:00:00 2001 From: Stig Bakken Date: Wed, 21 Apr 1999 22:49:16 +0000 Subject: [PATCH] moved dav, msql and oracle to ext/ --- Makefile.in | 8 +- acconfig.h.in | 15 - acinclude.m4 | 31 - configure.in.in | 211 +-- ext/dav/Makefile.am | 6 + ext/dav/config.h.stub | 2 + ext/dav/config.m4 | 29 + ext/dav/dav.c | 300 ++++ ext/dav/php3_dav.h | 63 + ext/dav/setup.stub | 2 + ext/ext_skel | 6 +- ext/msql/Makefile.am | 6 + ext/msql/config.h.stub | 2 + ext/msql/config.m4 | 49 + ext/msql/msql.c | 1452 +++++++++++++++++ ext/msql/php3_msql.h | 100 ++ ext/msql/setup.stub | 11 + ext/mysql/setup.stub | 9 +- ext/oracle/Makefile.am | 5 + ext/oracle/config.h.stub | 6 + ext/oracle/config.m4 | 162 ++ ext/oracle/oci8.c | 3172 ++++++++++++++++++++++++++++++++++++++ ext/oracle/oracle.c | 1715 +++++++++++++++++++++ ext/oracle/oracle.h | 157 ++ ext/oracle/oracle_hack.c | 24 + ext/oracle/php3_oci8.h | 190 +++ ext/oracle/setup.stub | 9 + internal_functions.c | 10 +- setup | 22 - 29 files changed, 7479 insertions(+), 295 deletions(-) create mode 100644 ext/dav/Makefile.am create mode 100644 ext/dav/config.h.stub create mode 100644 ext/dav/config.m4 create mode 100644 ext/dav/dav.c create mode 100644 ext/dav/php3_dav.h create mode 100644 ext/dav/setup.stub create mode 100644 ext/msql/Makefile.am create mode 100644 ext/msql/config.h.stub create mode 100644 ext/msql/config.m4 create mode 100644 ext/msql/msql.c create mode 100644 ext/msql/php3_msql.h create mode 100644 ext/msql/setup.stub create mode 100644 ext/oracle/Makefile.am create mode 100644 ext/oracle/config.h.stub create mode 100644 ext/oracle/config.m4 create mode 100644 ext/oracle/oci8.c create mode 100644 ext/oracle/oracle.c create mode 100644 ext/oracle/oracle.h create mode 100644 ext/oracle/oracle_hack.c create mode 100644 ext/oracle/php3_oci8.h create mode 100644 ext/oracle/setup.stub diff --git a/Makefile.in b/Makefile.in index 4c2c356952d..8542f082fc2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -71,18 +71,16 @@ OBJS = main.o internal_functions.o snprintf.o php3_sprintf.o \ FUNCTIONS_SOURCE = functions/apache.c functions/fhttpd.c \ functions/crypt.c functions/db.c functions/dl.c \ functions/head.c functions/imap.c functions/mime.c \ - functions/msql.c \ - functions/oracle.c functions/oci8.c functions/pgsql.c \ - functions/post.c functions/sybase.c \ + functions/pgsql.c functions/post.c functions/sybase.c \ functions/sybase-ct.c @BCMATH_SRC@ functions/xml.c \ functions/ldap.c functions/zlib.c functions/COM.c functions/ifx.c \ functions/pdf.c functions/hw.c functions/hg_comm.c functions/dlist.c \ functions/fdf.c functions/snmp.c functions/interbase.c \ - functions/sysvsem.c functions/sysvshm.c functions/dav.c + functions/sysvsem.c functions/sysvshm.c FUNCTIONS = $(FUNCTIONS_SOURCE:.c=.o) PHPLIBS = -L@top_srcdir@/libzend -lzend -Lext -lphpext -LIBS = $(PHPLIBS) $(EXTRA_LIBS) @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @FHTTPD_LIB@ @REGEX_LIB@ @DBM_LIB@ @ORACLE_LFLAGS@ @ORACLE_LIBS@ @SYBASE_LFLAGS@ @SYBASE_LIBS@ @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @MYSQL_LFLAGS@ @MYSQL_LIBS@ @MSQL_LFLAGS@ @MSQL_LIBS@ @PGSQL_LFLAGS@ @PGSQL_LIBS@ @LDAP_LFLAGS@ @LDAP_LIBS@ @IMAP_LIBS@ @ZLIB_LIBS@ @PDFLIB_LIBS@ @FDFLIB_LIBS@ @IFX_LFLAGS@ @IFX_LIBS@ @SNMP_LFLAGS@ @SNMP_LIBS@ @IBASE_LFLAGS@ @IBASE_LIBS@ @XML_LIBS@ @LIBS@ +LIBS = $(PHPLIBS) $(EXTRA_LIBS) @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @FHTTPD_LIB@ @REGEX_LIB@ @DBM_LIB@ @SYBASE_LFLAGS@ @SYBASE_LIBS@ @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @MYSQL_LFLAGS@ @MYSQL_LIBS@ @PGSQL_LFLAGS@ @PGSQL_LIBS@ @LDAP_LFLAGS@ @LDAP_LIBS@ @IMAP_LIBS@ @ZLIB_LIBS@ @PDFLIB_LIBS@ @FDFLIB_LIBS@ @IFX_LFLAGS@ @IFX_LIBS@ @SNMP_LFLAGS@ @SNMP_LIBS@ @IBASE_LFLAGS@ @IBASE_LIBS@ @XML_LIBS@ @LIBS@ all: $(BINNAME) diff --git a/acconfig.h.in b/acconfig.h.in index 6b3ded1a02f..f1ece7cefb7 100644 --- a/acconfig.h.in +++ b/acconfig.h.in @@ -70,12 +70,6 @@ /* Define if you have the crypt() function */ #define HAVE_CRYPT 1 -/* Define if you have the Oracle database client libraries */ -#define HAVE_ORACLE 0 - -/* Define if you have the Oracle version 8 database client libraries */ -#define HAVE_OCI8 0 - /* Define if you want the LDAP directory interface */ #define HAVE_LDAP 0 @@ -124,10 +118,6 @@ #define HAVE_SYBASE 0 #define HAVE_SYBASE_CT 0 -#ifndef HAVE_MSQL -#define HAVE_MSQL 0 -#endif - #ifndef HAVE_PGSQL #define HAVE_PGSQL 0 #endif @@ -150,8 +140,6 @@ #define HAVE_PQCMDTUPLES 0 #endif -#define MSQL1 0 - #ifndef DEBUG /* should be set to ZEND_DEBUG */ #define DEBUG 0 #endif @@ -209,6 +197,3 @@ /* Define if you have the fdftk library */ #define HAVE_FDFLIB 0 - -/* Define to compile with mod_dav support */ -#define HAVE_MOD_DAV 0 diff --git a/acinclude.m4 b/acinclude.m4 index d74390e8b0c..78ab84b136d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -2,37 +2,6 @@ dnl $Id$ dnl dnl This file contains local autoconf functions. -AC_DEFUN(AC_ORACLE_VERSION,[ - AC_MSG_CHECKING([Oracle version]) - if test -f "$ORACLEINST_TOP/orainst/unix.rgs" - then - ORACLE_VERSION=`grep '"ocommon"' $ORACLEINST_TOP/orainst/unix.rgs | sed 's/[ ][ ]*/:/g' | cut -d: -f 6 | cut -c 2-4` - test -z "$ORACLE_VERSION" && ORACLE_VERSION=7.3 - else - ORACLE_VERSION=8.0 - fi - AC_MSG_RESULT($ORACLE_VERSION) -]) - -dnl -dnl Test mSQL version by checking if msql.h has "IDX_TYPE" defined. -dnl -AC_DEFUN(AC_MSQL_VERSION,[ - AC_MSG_CHECKING([mSQL version]) - ac_php_oldcflags=$CFLAGS - CFLAGS="$MSQL_INCLUDE $CFLAGS"; - AC_TRY_COMPILE([#include -#include "msql.h"],[int i = IDX_TYPE],[ - AC_DEFINE(MSQL1,0) - MSQL_VERSION="2.0 or newer" - ],[ - AC_DEFINE(MSQL1,1) - MSQL_VERSION="1.0" - ]) - CFLAGS=$ac_php_oldcflags - AC_MSG_RESULT($MSQL_VERSION) -]) - dnl dnl See if we have broken header files like SunOS has. dnl diff --git a/configure.in.in b/configure.in.in index f740fea6a13..b226b6bdf7c 100644 --- a/configure.in.in +++ b/configure.in.in @@ -315,7 +315,7 @@ AC_ARG_WITH(apxs, withval=apxs fi APXS="$withval" - APXS_LDFLAGS="@ORACLE_LFLAGS@ @ORACLE_LIBS@ @IODBC_LFLAGS@ @IODBC_LIBS@ @SYBASE_LFLAGS@ @SYBASE_LIBS@ @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @MSQL_LFLAGS@ @MSQL_LIBS@ @ADA_LFLAGS@ @ADA_LIBS@ @SOLID_LIBS@ @EMPRESS_LIBS@ @OPENLINK_LIBS@ @PGSQL_LFLAGS@ @PGSQL_LIBS@ @LDAP_LFLAGS@ @LDAP_LIBS@ @VELOCIS_LIBS@ @CODBC_LFLAGS@ @CODBC_LIBS@ @ZLIB_LIBS@ @PDFLIB_LIBS@ @FDFTK_LIBS@ @IFX_LFLAGS@ @IFX_LIBS@ @IBASE_LFLAGS@ @IBASE_LIBS@" + APXS_LDFLAGS="@ORACLE_LFLAGS@ @ORACLE_LIBS@ @SYBASE_LFLAGS@ @SYBASE_LIBS@ @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @PGSQL_LFLAGS@ @PGSQL_LIBS@ @LDAP_LFLAGS@ @LDAP_LIBS@ @ZLIB_LIBS@ @PDFLIB_LIBS@ @FDFTK_LIBS@ @IFX_LFLAGS@ @IFX_LIBS@ @IBASE_LFLAGS@ @IBASE_LIBS@" APACHE_INCLUDE="-I`$APXS -q INCLUDEDIR`" BINNAME=libphp3.so INSTALL_IT="\$(APXS) -i -a -n php3 $BINNAME" @@ -871,158 +871,6 @@ dnl## AC_SUBST(IMAP_INCLUDE) ]) -AC_MSG_CHECKING(for Oracle support) -AC_ARG_WITH(oracle, -[ --with-oracle[=DIR] Include Oracle database support. DIR is Oracle's - home directory, defaults to \$ORACLE_HOME.], -[ - case "$withval" in - yes) - ORACLEINST_TOP=$ORACLE_HOME - AC_MSG_RESULT(yes) - ;; - no) - ORACLEINST_TOP= - AC_MSG_RESULT(no) - ;; - *) - AC_MSG_RESULT(yes) - ORACLEINST_TOP=$withval - ;; - esac - - if test "$ORACLEINST_TOP" != "" - then - - # Oracle include files - - if test -f "$ORACLEINST_TOP/rdbms/public/ocidfn.h" - then - # V8.0.5 - ORACLE_INCLUDE="$ORACLE_INCLUDE -I$ORACLEINST_TOP/rdbms/public" - elif test -f "$ORACLEINST_TOP/rdbms/demo/ocidfn.h" - then - # V7.[0123] - ORACLE_INCLUDE=-I$ORACLEINST_TOP/rdbms/demo - fi - - if test -d "$ORACLEINST_TOP/network/public" - then - # V8 - ORACLE_INCLUDE="$ORACLE_INCLUDE -I$ORACLEINST_TOP/network/public" - fi - - if test -d "$ORACLEINST_TOP/plsql/public" - then - # V8 - ORACLE_INCLUDE="$ORACLE_INCLUDE -I$ORACLEINST_TOP/plsql/public" - fi - - # Need to know the version, otherwhise we will mixup nlsrtl - AC_ORACLE_VERSION($ORACLEINST_TOP) - - # Oracle libs - nightmare :-) - - ORACLE_LIBDIR=lib - ORACLE_LFLAGS="-L$ORACLEINST_TOP/$ORACLE_LIBDIR ${ld_runpath_switch}$ORACLEINST_TOP/$ORACLE_LIBDIR" - if test -f "$ORACLEINST_TOP/rdbms/lib/sysliblist" - then - ORA_SYSLIB="`cat $ORACLEINST_TOP/rdbms/lib/sysliblist`" - else - ORA_SYSLIB="-lm" - fi - - # Oracle Static libs - case $ORACLE_VERSION in - 7.0|7.1) - ORACLE_STLIBS="-locic $ORACLEINST_TOP/$ORACLE_LIBDIR/osntab.o \ - -lsqlnet -lora -lsqlnet -lnlsrtl -lcv6 -lcore -lnlsrtl -lcv6 \ - -lcore $ORA_SYSLIB -lcore $ORA_SYSLIB" - if test "`uname -s 2>/dev/null`" = "AIX"; then - ORACLE_STLIBS="$ORACLE_STLIBS -bI:$ORACLE_HOME/lib/mili.exp" - fi - ;; - 7.2) - ORACLE_STLIBS="-locic $ORACLEINST_TOP/$ORACLE_LIBDIR/osntab.o \ - -lsqlnet -lora -lsqlnet -lora -lnlsrtl3 -lc3v6 -lcore3 -lnlsrtl3 \ - -lcore3 $ORA_SYSLIB -lcore3 $ORA_SYSLIB" - ;; - 7.3) - ORACLE_STLIBS="-lclient -lsqlnet -lncr -lsqlnet -lclient -lcommon \ - -lgeneric -lsqlnet -lncr -lsqlnet -lclient -lcommon -lgeneric \ - -lepc -lnlsrtl3 -lc3v6 -lcore3 -lnlsrtl3 -lcore3 -lnlsrtl3 \ - $ORA_SYSLIB -lcore3 $ORA_SYSLIB" - ;; - 8.0) - ORACLE_STLIBS="-lclient -lsqlnet -lncr -lsqlnet -lclient -lcommon \ - -lgeneric -lsqlnet -lncr -lsqlnet -lclient -lcommon -lgeneric \ - -lepc -lnlsrtl3 -lc3v6 -lcore4 -lnlsrtl3 -lcore4 -lnlsrtl3 \ - $ORA_SYSLIB -lcore3 $ORA_SYSLIB" - ;; - *) - ORACLE_STLIBS= - ;; - esac - - # Oracle shared libs - case $ORACLE_VERSION in - 7.0) - # shared libs not supported - ORACLE_SHLIBS="$ORACLE_STLIBS" - ;; - 7.1) - if test -f $ORACLEINST_TOP/$ORACLE_LIBDIR/liboracle.s? - then - ORACLE_SHLIBS="-loracle $ORA_SYSLIB" - else - ORACLE_SHLIBS="$ORACLE_STLIBS" - fi - ;; - 7.2|7.3) - if test -f $ORACLEINST_TOP/$ORACLE_LIBDIR/libclntsh.s? - then - ORACLE_SHLIBS="-lclntsh $ORA_SYSLIB" - else - ORACLE_SHLIBS="$ORACLE_STLIBS" - fi - ;; - 8.0) - if test -f $ORACLEINST_TOP/$ORACLE_LIBDIR/libclntsh.s? -o \ - -f $ORACLEINST_TOP/$ORACLE_LIBDIR/libclntsh.a # AIX - then - if test "$CC" = "gcc" -a "`uname -sv`" = "AIX 4"; then - # for Oracle 8 on AIX 4 - ORA_SYSLIB="$ORA_SYSLIB -nostdlib /lib/crt0_r.o /usr/lib/libpthreads.a /usr/lib/libc_r.a -lgcc" - fi - ORACLE_SHLIBS="-lclntsh -lpsa -lcore4 -lnlsrtl3 -lclntsh $ORA_SYSLIB" - else - ORACLE_SHLIBS="$ORACLE_STLIBS" - fi - AC_DEFINE(HAVE_OCI8) - ;; - *) - ORACLE_SHLIBS= - ;; - esac - - # only using shared libs right now - ORACLE_LIBS=$ORACLE_SHLIBS - - AC_DEFINE(HAVE_ORACLE) - - fi - -],[AC_MSG_RESULT(no)]) -AC_SUBST(ORACLE_SHLIBS) -AC_SUBST(ORACLE_STLIBS) -AC_SUBST(ORACLE_LIBS) -AC_SUBST(ORACLE_LFLAGS) -dnl## AC_SUBST(ORACLE_INCLUDE) -INCLUDES="$INCLUDES $ORACLE_INCLUDE" -AC_SUBST(ORACLE_HOME) -AC_SUBST(ORACLE_VERSION) - - AC_MSG_CHECKING(for Sybase support) AC_ARG_WITH(sybase, [ --with-sybase[=DIR] Include Sybase-DB support. DIR is the Sybase home @@ -1095,37 +943,6 @@ dnl## AC_SUBST(SYBASE_CT_INCLUDE) INCLUDES="$INCLUDES $SYBASE_CT_INCLUDE" -AC_MSG_CHECKING(for mSQL support) -AC_ARG_WITH(msql, -[ --with-msql[=DIR] Include mSQL support. DIR is the mSQL base - install directory, defaults to /usr/local/Hughes.], -[ - if test "$withval" != "no"; then - if test "$withval" = "yes"; then - MSQL_INCDIR=/usr/local/Hughes/include - MSQL_LIBDIR=/usr/local/Hughes/lib - else - MSQL_INCDIR=$withval/include - MSQL_LIBDIR=$withval/lib - fi - MSQL_INCLUDE=-I$MSQL_INCDIR - MSQL_LFLAGS=-L$MSQL_LIBDIR - MSQL_LIBS=-lmsql - - AC_DEFINE(HAVE_MSQL) - AC_MSG_RESULT(yes) - AC_MSQL_VERSION - else - AC_MSG_RESULT(no) - fi -],[ - AC_MSG_RESULT(no) -]) -AC_SUBST(MSQL_LIBS) -AC_SUBST(MSQL_LFLAGS) -dnl## AC_SUBST(MSQL_INCLUDE) -INCLUDES="$INCLUDES $MSQL_INCLUDE" - AC_MSG_CHECKING(for PostgresSQL support) AC_ARG_WITH(pgsql, [ --with-pgsql[=DIR] Include PostgresSQL support. DIR is the PostgresSQL @@ -1471,32 +1288,6 @@ dnl## AC_SUBST(FDFLIB_INCLUDE) INCLUDES="$INCLUDES $FDFLIB_INCLUDE" -AC_MSG_CHECKING(whether to enable DAV support through mod_dav) -AC_ARG_WITH(mod-dav, -[ --with-mod-dav=DIR Include DAV support through Apache's mod_dav, - DIR is mod_dav's installation directory (Apache - module version only!)], -[ - if test "$withval" = "yes"; then - AC_MSG_ERROR(Must give parameter to --with-mod-dav!) - else - if test "$withval" != "no"; then - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_MOD_DAV, 1) - MOD_DAV_CFLAGS="-DHAVE_MOD_DAV -I$withval" - INCLUDES="$INCLUDES -I$withval" - else - AC_MSG_RESULT(no) - AC_DEFINE(HAVE_MOD_DAV, 0) - fi - fi -],[ - AC_MSG_RESULT(no) - AC_DEFINE(HAVE_MOD_DAV, 0) -]) -AC_SUBST(MOD_DAV_CFLAGS) - - AC_MSG_CHECKING(whether to enable System V semaphore support) AC_ARG_ENABLE(sysvsem, [ --enable-sysvsem Enable System V semaphore support.], diff --git a/ext/dav/Makefile.am b/ext/dav/Makefile.am new file mode 100644 index 00000000000..58f9fe10097 --- /dev/null +++ b/ext/dav/Makefile.am @@ -0,0 +1,6 @@ +# $Id$ + +INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend +noinst_LIBRARIES=libphpext_dav.a +libphpext_dav_a_SOURCES=dav.c + diff --git a/ext/dav/config.h.stub b/ext/dav/config.h.stub new file mode 100644 index 00000000000..90a0bc1de46 --- /dev/null +++ b/ext/dav/config.h.stub @@ -0,0 +1,2 @@ +/* Define to compile with mod_dav support */ +#define HAVE_MOD_DAV 0 diff --git a/ext/dav/config.m4 b/ext/dav/config.m4 new file mode 100644 index 00000000000..c2b83adbc72 --- /dev/null +++ b/ext/dav/config.m4 @@ -0,0 +1,29 @@ +dnl $Id$ +dnl config.m4 for extension dav +dnl don't forget to call PHP_EXTENSION(dav) + +AC_MSG_CHECKING(whether to enable DAV support through mod_dav) +AC_ARG_WITH(mod-dav, +[ --with-mod-dav=DIR Include DAV support through Apache's mod_dav, + DIR is mod_dav's installation directory (Apache + module version only!)], +[ + if test "$withval" = "yes"; then + AC_MSG_ERROR(Must give parameter to --with-mod-dav!) + else + if test "$withval" != "no"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_MOD_DAV, 1) + CFLAGS="$CFLAGS -DHAVE_MOD_DAV -I$withval" + INCLUDES="$INCLUDES -I$withval" + PHP_EXTENSION(dav) + else + AC_MSG_RESULT(no) + AC_DEFINE(HAVE_MOD_DAV, 0) + fi + fi +],[ + AC_MSG_RESULT(no) + AC_DEFINE(HAVE_MOD_DAV, 0) +]) + diff --git a/ext/dav/dav.c b/ext/dav/dav.c new file mode 100644 index 00000000000..967b1a6757a --- /dev/null +++ b/ext/dav/dav.c @@ -0,0 +1,300 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997,1998 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Stig Sæther Bakken | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#define IS_EXT_MODULE +#if COMPILE_DL +# if PHP_31 +# include "../phpdl.h" +# else +# include "dl/phpdl.h" +# endif +#endif +#include "php.h" +#include "php3_dav.h" + +#if defined(THREAD_SAFE) && !PHP_31 +# undef THREAD_SAFE +#endif + +#if HAVE_MOD_DAV + +# include "mod_dav.h" +# include "phpdav.h" +# include "variables.h" + +/* {{{ thread safety stuff */ + +# ifdef THREAD_SAFE +# define DAV_GLOBAL(a) phpdav_globals->a +# define DAV_TLS_VARS phpdav_global_struct *phpdav_globals = TlsGetValue(PHPDAVTls); + +void *phpdav_mutex; +DWORD PHPDAVTls; +static int numthreads=0; + +typedef struct phpdav_global_struct { + phpdav_module php3_dav_module; +} phpdav_global_struct; + +# else /* !defined(THREAD_SAFE) */ +# define DAV_GLOBAL(a) a +# define DAV_TLS_VARS + +phpdav_module php3_dav_module; + +# endif /* defined(THREAD_SAFE) */ + +# define DAV_HANDLER(a) DAV_GLOBAL(php3_dav_module).a##_handler +# define DAV_SET_HANDLER(a,b) \ + dav_set_handler(&DAV_GLOBAL(php3_dav_module).a##_handler,(b)) + + +/* }}} */ +/* {{{ dynamically loadable module stuff */ + +# if COMPILE_DL +DLEXPORT php3_module_entry *get_module() { return &phpdav_module_entry; }; +# endif /* COMPILE_DL */ + +/* }}} */ +/* {{{ function prototypes */ + +int php3_minit_phpdav(INIT_FUNC_ARGS); +int php3_rinit_phpdav(INIT_FUNC_ARGS); +int php3_mshutdown_phpdav(SHUTDOWN_FUNC_ARGS); +int php3_rshutdown_phpdav(SHUTDOWN_FUNC_ARGS); +void php3_info_phpdav(void); + +/* }}} */ +/* {{{ extension definition structures */ + +function_entry phpdav_functions[] = { + PHP_FE(dav_set_mkcol_handlers, NULL) + {NULL, NULL, NULL} +}; + +php3_module_entry phpdav_module_entry = { + "DAV", /* extension name */ + phpdav_functions, /* extension function list */ + php3_minit_phpdav, /* extension-wide startup function */ + php3_mshutdown_phpdav, /* extension-wide shutdown function */ + php3_rinit_phpdav, /* per-request startup function */ + php3_rshutdown_phpdav, /* per-request shutdown function */ + php3_info_phpdav, /* information function */ + STANDARD_MODULE_PROPERTIES +}; + +/* }}} */ +/* {{{ startup, shutdown and info functions */ + + /* {{{ php3_minit_phpdav */ + +int php3_minit_phpdav(INIT_FUNC_ARGS) +{ +#if defined(THREAD_SAFE) + phpdav_global_struct *phpdav_globals; + PHP3_MUTEX_ALLOC(phpdav_mutex); + PHP3_MUTEX_LOCK(phpdav_mutex); + numthreads++; + if (numthreads==1){ + if (!PHP3_TLS_PROC_STARTUP(PHPDAVTls)){ + PHP3_MUTEX_UNLOCK(phpdav_mutex); + PHP3_MUTEX_FREE(phpdav_mutex); + return FAILURE; + } + } + PHP3_MUTEX_UNLOCK(phdpav_mutex); + if(!PHP3_TLS_THREAD_INIT(PHPDAVTls,phpdav_globals,phpdav_global_struct)){ + PHP3_MUTEX_FREE(phpdav_mutex); + return FAILURE; + } +#endif + return SUCCESS; +} + +/* }}} */ + /* {{{ php3_rinit_phpdav */ + +int php3_rinit_phpdav(INIT_FUNC_ARGS) +{ + return SUCCESS; +} + +/* }}} */ + /* {{{ php3_mshutdown_phpdav() */ + +int php3_mshutdown_phpdav(SHUTDOWN_FUNC_ARGS) +{ + DAV_TLS_VARS; +#ifdef THREAD_SAFE + PHP3_TLS_THREAD_FREE(phpdav_globals); + PHP3_MUTEX_LOCK(phpdav_mutex); + numthreads--; + if (numthreads < 1) { + PHP3_TLS_PROC_SHUTDOWN(PHPDAVTls); + PHP3_MUTEX_UNLOCK(phpdav_mutex); + PHP3_MUTEX_FREE(phpdav_mutex); + return SUCCESS; + } + PHP3_MUTEX_UNLOCK(phpdav_mutex); +#endif + return SUCCESS; +} + +/* }}} */ + /* {{{ php3_rshutdown_phpdav() */ + +int php3_rshutdown_phpdav(SHUTDOWN_FUNC_ARGS) +{ + if (DAV_HANDLER(mkcol_test)) { + efree(DAV_HANDLER(mkcol_test)); + } + if (DAV_HANDLER(mkcol_create)) { + efree(DAV_HANDLER(mkcol_create)); + } + return SUCCESS; +} + +/* }}} */ + /* {{{ php3_info_phpdav() */ + +void php3_info_phpdav() +{ +} + +/* }}} */ + +/* }}} */ +/* {{{ extension-internal functions */ + + /* {{{ dav_set_handler() */ + +static void +dav_set_handler(char **nameBufp, pval *data) +{ + if (data->value.str.len > 0) { + if (*nameBufp != NULL) { + efree(*nameBufp); + } + *nameBufp = php3i_pval_strdup(data); + } else { + if (*nameBufp != NULL) { + efree(*nameBufp); + } + *nameBufp = NULL; + } +} + +/* }}} */ + /* {{{ dav_call_handler() */ + +static int +dav_call_handler(char *funcName, int argc, pval **argv) +{ + if (funcName) { + pval *retval, *func; + int i, ret; + HashTable *function_table; + + func = php3i_string_pval(funcName); + retval = emalloc(sizeof(pval)); + function_table = php3i_get_function_table(); + if (call_user_function(function_table, NULL, func, retval, argc, argv) == FAILURE) { + php3tls_pval_destructor(retval); + efree(retval); + return HTTP_INTERNAL_SERVER_ERROR; + } + php3tls_pval_destructor(func); + efree(func); + for (i = 0; i < argc; i++) { + php3tls_pval_destructor(argv[i]); + efree(argv[i]); + } + convert_to_long(retval); + ret = retval->value.lval; + efree(retval); + return ret; + } + return DECLINED; +} + +/* }}} */ + +int phpdav_mkcol_test_handler(request_rec *r) +{ + pval *arg; + + if (DAV_HANDLER(mkcol_test) == NULL) { + return DECLINED; + } + arg = php3i_string_pval(r->filename); + return dav_call_handler(DAV_HANDLER(mkcol_test), 1, &arg); +} + +int phpdav_mkcol_create_handler(request_rec *r) +{ + pval *arg; + + if (DAV_HANDLER(mkcol_create) == NULL) { + return DECLINED; + } + arg = php3i_string_pval(r->filename); + return dav_call_handler(DAV_HANDLER(mkcol_create), 1, &arg); +} + +/* }}} */ + +/************************* EXTENSION FUNCTIONS *************************/ + +/* {{{ proto void dav_set_mkcol_handlers(string test, string create) + Sets the function to test whether a DAV collection exists for MKCOL */ +PHP_FUNCTION(dav_set_mkcol_handlers) +{ + pval *test, *create; + DAV_TLS_VARS; + + if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &test, &create) == FAILURE) { + WRONG_PARAM_COUNT; + } + DAV_SET_HANDLER(mkcol_test, test); + DAV_SET_HANDLER(mkcol_create, create); + RETVAL_TRUE; +} +/* }}} */ + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/ext/dav/php3_dav.h b/ext/dav/php3_dav.h new file mode 100644 index 00000000000..a66525331dc --- /dev/null +++ b/ext/dav/php3_dav.h @@ -0,0 +1,63 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997,1998 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Stig Sæther Bakken | + +----------------------------------------------------------------------+ + */ + +/* $Id */ + +#ifndef _PHP_DAV_H +# define _PHP_DAV_H + +# if HAVE_MOD_DAV + +typedef struct { + int foo; + char *mkcol_test_handler; + char *mkcol_create_handler; +} phpdav_module; + +extern php3_module_entry phpdav_module_entry; +# define phpdav_module_ptr &phpdav_module_entry + +int phpdav_mkcol_test_handler(request_rec *); + +PHP_FUNCTION(dav_set_mkcol_handlers); + +# else /* !HAVE_MOD_DAV */ + +# define phpdav_module_ptr NULL + +# endif /* HAVE_MOD_DAV */ + +#endif /* _PHP_DAV_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/ext/dav/setup.stub b/ext/dav/setup.stub new file mode 100644 index 00000000000..881144c1caf --- /dev/null +++ b/ext/dav/setup.stub @@ -0,0 +1,2 @@ +# $Id$ +# This extension is still very much under construction. diff --git a/ext/ext_skel b/ext/ext_skel index 5b533eace4b..30ea4fafd96 100755 --- a/ext/ext_skel +++ b/ext/ext_skel @@ -35,11 +35,11 @@ eof echo -n " setup.stub" cat >setup.stub < +#include "msql.h"],[int i = IDX_TYPE],[ + AC_DEFINE(MSQL1,0) + MSQL_VERSION="2.0 or newer" + ],[ + AC_DEFINE(MSQL1,1) + MSQL_VERSION="1.0" + ]) + CFLAGS=$ac_php_oldcflags + AC_MSG_RESULT($MSQL_VERSION) +]) + +AC_MSG_CHECKING(for mSQL support) +AC_ARG_WITH(msql, +[ --with-msql[=DIR] Include mSQL support. DIR is the mSQL base + install directory, defaults to /usr/local/Hughes.], +[ + if test "$withval" != "no"; then + if test "$withval" = "yes"; then + MSQL_INCDIR=/usr/local/Hughes/include + MSQL_LIBDIR=/usr/local/Hughes/lib + else + MSQL_INCDIR=$withval/include + MSQL_LIBDIR=$withval/lib + fi + MSQL_INCLUDE=-I$MSQL_INCDIR + MSQL_LFLAGS=-L$MSQL_LIBDIR + MSQL_LIBS=-lmsql + AC_DEFINE(HAVE_MSQL) + AC_MSG_RESULT(yes) + PHP_EXTENSION(msql) + AC_MSQL_VERSION + else + AC_MSG_RESULT(no) + fi +],[ + AC_MSG_RESULT(no) +]) +EXTRA_LIBS="$EXTRA_LIBS $MSQL_LFLAGS $MSQL_LIBS" +INCLUDES="$INCLUDES $MSQL_INCLUDE" diff --git a/ext/msql/msql.c b/ext/msql/msql.c new file mode 100644 index 00000000000..dbeb4c7f388 --- /dev/null +++ b/ext/msql/msql.c @@ -0,0 +1,1452 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997,1998 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Zeev Suraski | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ +#ifdef THREAD_SAFE +#include "tls.h" +#endif + +#include "php.h" +#if COMPILE_DL +#include "dl/phpdl.h" +#include "functions/dl.h" +#endif +#include "php3_msql.h" +#include "ext/standard/php3_standard.h" +#include "php_globals.h" + +#if HAVE_MSQL + +#if defined(WIN32) && defined(MSQL1) +#include +#else +#include +#endif + +#ifdef THREAD_SAFE +DWORD MSQLTls; +static int numthreads=0; + +typedef struct msql_global_struct{ + msql_module php3_msql_module; +}msql_global_struct; + +#define MSQL_GLOBAL(a) msql_globals->a + +#define MSQL_TLS_VARS \ + msql_global_struct *msql_globals; \ + msql_globals=TlsGetValue(MSQLTls); + +#else +#define MSQL_GLOBAL(a) a +#define MSQL_TLS_VARS +msql_module php3_msql_module; +#endif + +function_entry msql_functions[] = { + {"msql_connect", php3_msql_connect, NULL}, + {"msql_pconnect", php3_msql_pconnect, NULL}, + {"msql_close", php3_msql_close, NULL}, + {"msql_select_db", php3_msql_select_db, NULL}, + {"msql_create_db", php3_msql_create_db, NULL}, + {"msql_drop_db", php3_msql_drop_db, NULL}, + {"msql_query", php3_msql_query, NULL}, + {"msql_db_query", php3_msql_db_query, NULL}, + {"msql_list_dbs", php3_msql_list_dbs, NULL}, + {"msql_list_tables", php3_msql_list_tables, NULL}, + {"msql_list_fields", php3_msql_list_fields, NULL}, + {"msql_error", php3_msql_error, NULL}, + {"msql_result", php3_msql_result, NULL}, + {"msql_num_rows", php3_msql_num_rows, NULL}, + {"msql_num_fields", php3_msql_num_fields, NULL}, + {"msql_fetch_row", php3_msql_fetch_row, NULL}, + {"msql_fetch_array", php3_msql_fetch_array, NULL}, + {"msql_fetch_object", php3_msql_fetch_object, NULL}, + {"msql_data_seek", php3_msql_data_seek, NULL}, + {"msql_fetch_field", php3_msql_fetch_field, NULL}, + {"msql_field_seek", php3_msql_field_seek, NULL}, + {"msql_free_result", php3_msql_free_result, NULL}, + {"msql_field_name", php3_msql_field_name, NULL}, + {"msql_field_table", php3_msql_field_table, NULL}, + {"msql_field_len", php3_msql_field_len, NULL}, + {"msql_field_type", php3_msql_field_type, NULL}, + {"msql_field_flags", php3_msql_field_flags, NULL}, + {"msql_fieldname", php3_msql_field_name, NULL}, + {"msql_fieldtable", php3_msql_field_table, NULL}, + {"msql_fieldlen", php3_msql_field_len, NULL}, + {"msql_fieldtype", php3_msql_field_type, NULL}, + {"msql_fieldflags", php3_msql_field_flags, NULL}, + + {"msql_regcase", php3_sql_regcase, NULL}, + {"msql_affected_rows", php3_msql_affected_rows, NULL}, + /* for downwards compatability */ + {"msql", php3_msql_db_query, NULL}, + {"msql_selectdb", php3_msql_select_db, NULL}, + {"msql_createdb", php3_msql_create_db, NULL}, + {"msql_dropdb", php3_msql_drop_db, NULL}, + {"msql_freeresult", php3_msql_free_result, NULL}, + {"msql_numfields", php3_msql_num_fields, NULL}, + {"msql_numrows", php3_msql_num_rows, NULL}, + {"msql_listdbs", php3_msql_list_dbs, NULL}, + {"msql_listtables", php3_msql_list_tables, NULL}, + {"msql_listfields", php3_msql_list_fields, NULL}, + {"msql_dbname", php3_msql_result, NULL}, + {"msql_tablename", php3_msql_result, NULL}, + {NULL, NULL, NULL} +}; + + +php3_module_entry msql_module_entry = { + "mSQL", msql_functions, php3_minit_msql, php3_mshutdown_msql, php3_rinit_msql, NULL, php3_info_msql, STANDARD_MODULE_PROPERTIES +}; + + +#if COMPILE_DL +DLEXPORT php3_module_entry *get_module(void) { return &msql_module_entry; } +#if (WIN32|WINNT) && defined(THREAD_SAFE) + +/*NOTE: You should have an odbc.def file where you +export DllMain*/ +BOOL WINAPI DllMain(HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) +{ + switch( ul_reason_for_call ) { + case DLL_PROCESS_ATTACH: + if ((MSQLTls=TlsAlloc())==0xFFFFFFFF){ + return 0; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + if (!TlsFree(MSQLTls)){ + return 0; + } + break; + } + return 1; +} +#endif +#endif + +typedef struct { + m_result *result; + int af_rows; +} m_query; + +#define MSQL_GET_QUERY(res) \ + convert_to_long((res)); \ + msql_query = (m_query *) php3_list_find((res)->value.lval,&type); \ + if (type!=MSQL_GLOBAL(php3_msql_module).le_query) { \ + php3_error(E_WARNING,"%d is not a mSQL query index", \ + res->value.lval); \ + RETURN_FALSE; \ + } \ + msql_result = msql_query->result + +static void _delete_query(void *arg) +{ + m_query *query = (m_query *) arg; + + if(query->result) msqlFreeResult(query->result); + efree(arg); +} + +#define _new_query(a,b) \ + __new_query(INTERNAL_FUNCTION_PARAM_PASSTHRU,a,b) + +static int __new_query(INTERNAL_FUNCTION_PARAMETERS, m_result *res, int af_rows) +{ + m_query *query = (m_query *) emalloc(sizeof(m_query)); + + query->result = res; + query->af_rows = af_rows; + + return (php3_list_insert((void *) query, + MSQL_GLOBAL(php3_msql_module).le_query)); +} + +static void _close_msql_link(int link) +{ + MSQL_TLS_VARS; + msqlClose(link); + MSQL_GLOBAL(php3_msql_module).num_links--; +} + + +static void _close_msql_plink(int link) +{ + MSQL_TLS_VARS; + msqlClose(link); + MSQL_GLOBAL(php3_msql_module).num_persistent--; + MSQL_GLOBAL(php3_msql_module).num_links--; +} + +DLEXPORT int php3_minit_msql(INIT_FUNC_ARGS) +{ +#ifdef THREAD_SAFE + msql_global_struct *msql_globals; +#if !COMPILE_DL + CREATE_MUTEX(msql_mutex,"MSQL_TLS"); + SET_MUTEX(msql_mutex); + numthreads++; + if (numthreads==1){ + if ((MSQLTls=TlsAlloc())==0xFFFFFFFF){ + FREE_MUTEX(msql_mutex); + return 0; + }} + FREE_MUTEX(msql_mutex); +#endif + msql_globals = (msql_global_struct *) LocalAlloc(LPTR, sizeof(msql_global_struct)); + TlsSetValue(MSQLTls, (void *) msql_globals); +#endif + + if (cfg_get_long("msql.allow_persistent",&MSQL_GLOBAL(php3_msql_module).allow_persistent)==FAILURE) { + MSQL_GLOBAL(php3_msql_module).allow_persistent=1; + } + if (cfg_get_long("msql.max_persistent",&MSQL_GLOBAL(php3_msql_module).max_persistent)==FAILURE) { + MSQL_GLOBAL(php3_msql_module).max_persistent=-1; + } + if (cfg_get_long("msql.max_links",&MSQL_GLOBAL(php3_msql_module).max_links)==FAILURE) { + MSQL_GLOBAL(php3_msql_module).max_links=-1; + } + MSQL_GLOBAL(php3_msql_module).num_persistent=0; + MSQL_GLOBAL(php3_msql_module).le_query = register_list_destructors(_delete_query,NULL); + MSQL_GLOBAL(php3_msql_module).le_link = register_list_destructors(_close_msql_link,NULL); + MSQL_GLOBAL(php3_msql_module).le_plink = register_list_destructors(NULL,_close_msql_plink); + + msql_module_entry.type = type; + + return SUCCESS; +} + +DLEXPORT int php3_mshutdown_msql(SHUTDOWN_FUNC_ARGS){ +#ifdef THREAD_SAFE + msql_global_struct *msql_globals; + msql_globals = TlsGetValue(MSQLTls); + if (msql_globals != 0) + LocalFree((HLOCAL) msql_globals); +#if !COMPILE_DL + SET_MUTEX(msql_mutex); + numthreads--; + if (!numthreads){ + if (!TlsFree(MSQLTls)){ + FREE_MUTEX(msql_mutex); + return 0; + }} + FREE_MUTEX(msql_mutex); +#endif +#endif + return SUCCESS; +} + +DLEXPORT int php3_rinit_msql(INIT_FUNC_ARGS) +{ + MSQL_TLS_VARS; + MSQL_GLOBAL(php3_msql_module).default_link=-1; + MSQL_GLOBAL(php3_msql_module).num_links = MSQL_GLOBAL(php3_msql_module).num_persistent; + msqlErrMsg[0]=0; + return SUCCESS; +} + +DLEXPORT void php3_info_msql(void) +{ + char maxp[16],maxl[16]; + MSQL_TLS_VARS; + + if (MSQL_GLOBAL(php3_msql_module).max_persistent==-1) { + strcpy(maxp,"Unlimited"); + } else { + snprintf(maxp,15,"%ld",MSQL_GLOBAL(php3_msql_module).max_persistent); + maxp[15]=0; + } + if (MSQL_GLOBAL(php3_msql_module).max_links==-1) { + strcpy(maxl,"Unlimited"); + } else { + snprintf(maxl,15,"%ld",MSQL_GLOBAL(php3_msql_module).max_links); + maxl[15]=0; + } + php3_printf("" + "\n" + "\n" + "\n" + "
Allow persistent links:%s
Persistent links:%d/%s
Total links:%d/%s
\n", + (MSQL_GLOBAL(php3_msql_module).allow_persistent?"Yes":"No"), + MSQL_GLOBAL(php3_msql_module).num_persistent,maxp, + MSQL_GLOBAL(php3_msql_module).num_links,maxl); +} + + +static void php3_msql_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent) +{ + char *host; + char *hashed_details; + int hashed_details_length; + int msql; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 0: /* defaults */ + host=NULL; + hashed_details=estrndup("msql_",5); + hashed_details_length=4+1; + break; + case 1: { + pval *yyhost; + + if (getParameters(ht, 1, &yyhost) == FAILURE) { + RETURN_FALSE; + } + convert_to_string(yyhost); + host = yyhost->value.str.val; + hashed_details_length = yyhost->value.str.len+4+1; + hashed_details = emalloc(hashed_details_length+1); + sprintf(hashed_details,"msql_%s",yyhost->value.str.val); /* SAFE */ + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + + if (!MSQL_GLOBAL(php3_msql_module).allow_persistent) { + persistent=0; + } + if (persistent) { + list_entry *le; + + if (MSQL_GLOBAL(php3_msql_module).max_links!=-1 && MSQL_GLOBAL(php3_msql_module).num_links>=MSQL_GLOBAL(php3_msql_module).max_links) { + php3_error(E_WARNING,"mSQL: Too many open links (%d)",MSQL_GLOBAL(php3_msql_module).num_links); + efree(hashed_details); + RETURN_FALSE; + } + if (MSQL_GLOBAL(php3_msql_module).max_persistent!=-1 && MSQL_GLOBAL(php3_msql_module).num_persistent>=MSQL_GLOBAL(php3_msql_module).max_persistent) { + php3_error(E_WARNING,"mSQL: Too many open persistent links (%d)",MSQL_GLOBAL(php3_msql_module).num_persistent); + efree(hashed_details); + RETURN_FALSE; + } + + /* try to find if we already have this link in our persistent list */ + if (_php3_hash_find(plist, hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) { /* we don't */ + list_entry new_le; + + /* create the link */ + if ((msql=msqlConnect(host))==-1) { + efree(hashed_details); + RETURN_FALSE; + } + + /* hash it up */ + new_le.type = MSQL_GLOBAL(php3_msql_module).le_plink; + new_le.ptr = (void *) msql; + if (_php3_hash_update(plist, hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(list_entry), NULL)==FAILURE) { + efree(hashed_details); + RETURN_FALSE; + } + MSQL_GLOBAL(php3_msql_module).num_persistent++; + MSQL_GLOBAL(php3_msql_module).num_links++; + } else { /* we do */ + if (le->type != MSQL_GLOBAL(php3_msql_module).le_plink) { + efree(hashed_details); + RETURN_FALSE; + } +#if 0 + /* ensure that the link did not die */ + /* still have to find a way to do this nicely with mSQL */ + if (msql_stat(le->ptr)==NULL) { /* the link died */ + if (msql_connect(le->ptr,host,user,passwd)==NULL) { + php3_error(E_WARNING,"mSQL link lost, unable to reconnect"); + _php3_hash_del(plist,hashed_details,hashed_details_length+1); + efree(hashed_details); + RETURN_FALSE; + } + } +#endif + msql = (int) le->ptr; + } + return_value->value.lval = php3_list_insert((void *)msql,MSQL_GLOBAL(php3_msql_module).le_plink); + return_value->type = IS_LONG; + } else { + list_entry *index_ptr,new_index_ptr; + + /* first we check the hash for the hashed_details key. if it exists, + * it should point us to the right offset where the actual msql link sits. + * if it doesn't, open a new msql link, add it to the resource list, + * and add a pointer to it with hashed_details as the key. + */ + if (_php3_hash_find(list,hashed_details,hashed_details_length+1,(void **) &index_ptr)==SUCCESS) { + int type,link; + void *ptr; + + if (index_ptr->type != le_index_ptr) { + RETURN_FALSE; + } + link = (int) index_ptr->ptr; + ptr = php3_list_find(link,&type); /* check if the link is still there */ + if (ptr && (type==MSQL_GLOBAL(php3_msql_module).le_link || type==MSQL_GLOBAL(php3_msql_module).le_plink)) { + return_value->value.lval = MSQL_GLOBAL(php3_msql_module).default_link = link; + return_value->type = IS_LONG; + efree(hashed_details); + return; + } else { + _php3_hash_del(list,hashed_details,hashed_details_length+1); + } + } + if (MSQL_GLOBAL(php3_msql_module).max_links!=-1 && MSQL_GLOBAL(php3_msql_module).num_links>=MSQL_GLOBAL(php3_msql_module).max_links) { + php3_error(E_WARNING,"mSQL: Too many open links (%d)",MSQL_GLOBAL(php3_msql_module).num_links); + efree(hashed_details); + RETURN_FALSE; + } + if ((msql=msqlConnect(host))==-1) { + efree(hashed_details); + RETURN_FALSE; + } + + /* add it to the list */ + return_value->value.lval = php3_list_insert((void *)msql,MSQL_GLOBAL(php3_msql_module).le_link); + return_value->type = IS_LONG; + + /* add it to the hash */ + new_index_ptr.ptr = (void *) return_value->value.lval; + new_index_ptr.type = le_index_ptr; + if (_php3_hash_update(list,hashed_details,hashed_details_length+1,(void *) &new_index_ptr, sizeof(list_entry), NULL)==FAILURE) { + efree(hashed_details); + RETURN_FALSE; + } + MSQL_GLOBAL(php3_msql_module).num_links++; + } + efree(hashed_details); + MSQL_GLOBAL(php3_msql_module).default_link=return_value->value.lval; +} + +static int php3_msql_get_default_link(INTERNAL_FUNCTION_PARAMETERS) +{ + MSQL_TLS_VARS; + if (MSQL_GLOBAL(php3_msql_module).default_link==-1) { /* no link opened yet, implicitly open one */ + HashTable tmp; + + _php3_hash_init(&tmp,0,NULL,NULL,0); + php3_msql_do_connect(&tmp,return_value,list,plist,0); + _php3_hash_destroy(&tmp); + } + return MSQL_GLOBAL(php3_msql_module).default_link; +} + +/* {{{ proto int msql_connect([string hostname[:port]] [, string username] [, string password]) + Open a connection to an mSQL Server */ +DLEXPORT void php3_msql_connect(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); +} +/* }}} */ + +/* {{{ proto int msql_pconnect([string hostname[:port]] [, string username] [, string password]) + Open a persistent connection to an mSQL Server */ +DLEXPORT void php3_msql_pconnect(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1); +} +/* }}} */ + +/* {{{ proto int msql_close([int link_identifier]) + Close an mSQL connection */ +DLEXPORT void php3_msql_close(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *msql_link; + int id,type; + int msql; + MSQL_TLS_VARS; + + switch (ARG_COUNT(ht)) { + case 0: + id = MSQL_GLOBAL(php3_msql_module).default_link; + break; + case 1: + if (getParameters(ht, 1, &msql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + php3_list_delete(id); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int msql_select_db(string database_name [, int link_identifier]) + Select an mSQL database */ +DLEXPORT void php3_msql_select_db(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *db,*msql_link; + int id,type; + int msql; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &db)==FAILURE) { + RETURN_FALSE; + } + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 2: + if (getParameters(ht, 2, &db, &msql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(db); + + if (msqlSelectDB(msql,db->value.str.val)==-1) { + RETURN_FALSE; + } else { + RETURN_TRUE; + } +} +/* }}} */ + +/* {{{ proto int msql_create_db(string database_name [, int link_identifier]) + Create an mSQL database */ +DLEXPORT void php3_msql_create_db(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *db,*msql_link; + int id,type; + int msql; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &db)==FAILURE) { + WRONG_PARAM_COUNT; + } + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 2: + if (getParameters(ht, 2, &db, &msql_link)==FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(db); + if (msqlCreateDB(msql,db->value.str.val)<0) { + RETURN_FALSE; + } else { + RETURN_TRUE; + } +} +/* }}} */ + +/* {{{ proto int msql_drop_db(string database_name [, int link_identifier]) + Drop (delete) an mSQL database */ +DLEXPORT void php3_msql_drop_db(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *db,*msql_link; + int id,type; + int msql; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &db)==FAILURE) { + WRONG_PARAM_COUNT; + } + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 2: + if (getParameters(ht, 2, &db, &msql_link)==FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(db); + if (msqlDropDB(msql,db->value.str.val)<0) { + RETURN_FALSE; + } else { + RETURN_TRUE; + } +} +/* }}} */ + +/* {{{ proto int msql_query(string query [, int link_identifier]) + Send an SQL query to mSQL */ +DLEXPORT void php3_msql_query(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *query,*msql_link; + int id,type; + int msql; + int af_rows; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &query)==FAILURE) { + WRONG_PARAM_COUNT; + } + id = MSQL_GLOBAL(php3_msql_module).default_link; + break; + case 2: + if (getParameters(ht, 2, &query, &msql_link)==FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(query); + if ((af_rows = msqlQuery(msql,query->value.str.val))==-1) { + RETURN_FALSE; + } + RETVAL_LONG(_new_query(msqlStoreResult(), af_rows)); +} +/* }}} */ + +/* {{{ proto int msql_db_query(string database_name, string query [, int link_identifier]) + Send an SQL query to mSQL */ +DLEXPORT void php3_msql_db_query(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *db,*query,*msql_link; + int id,type; + int msql; + int af_rows; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 2: + if (getParameters(ht, 2, &db, &query)==FAILURE) { + RETURN_FALSE; + } + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 3: + if (getParameters(ht, 3, &db, &query, &msql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(db); + if (msqlSelectDB(msql,db->value.str.val)==-1) { + RETURN_FALSE; + } + + convert_to_string(query); + if ((af_rows = msqlQuery(msql,query->value.str.val))==-1) { + RETURN_FALSE; + } + RETVAL_LONG(_new_query(msqlStoreResult(), af_rows)); +} +/* }}} */ + +/* {{{ proto int msql_list_dbs([int link_identifier]) + List databases available on an mSQL server */ +DLEXPORT void php3_msql_list_dbs(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *msql_link; + int id,type; + int msql; + m_result *msql_result; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 0: + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 1: + if (getParameters(ht, 1, &msql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + if ((msql_result=msqlListDBs(msql))==NULL) { + php3_error(E_WARNING,"Unable to save mSQL query result"); + RETURN_FALSE; + } + RETVAL_LONG(_new_query(msql_result, 0)); +} +/* }}} */ + +/* {{{ proto int msql_list_tables(string database_name [, int link_identifier]) + List tables in an mSQL database */ +DLEXPORT void php3_msql_list_tables(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *db,*msql_link; + int id,type; + int msql; + m_result *msql_result; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &db)==FAILURE) { + RETURN_FALSE; + } + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 2: + if (getParameters(ht, 2, &db, &msql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(db); + if (msqlSelectDB(msql,db->value.str.val)==-1) { + RETURN_FALSE; + } + if ((msql_result=msqlListTables(msql))==NULL) { + php3_error(E_WARNING,"Unable to save mSQL query result"); + RETURN_FALSE; + } + RETVAL_LONG(_new_query(msql_result, 0)); +} +/* }}} */ + +/* {{{ proto int msql_list_fields(string database_name, string table_name [, int link_identifier]) + List mSQL result fields */ +DLEXPORT void php3_msql_list_fields(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *db,*table,*msql_link; + int id,type; + int msql; + m_result *msql_result; + MSQL_TLS_VARS; + + switch(ARG_COUNT(ht)) { + case 2: + if (getParameters(ht, 2, &db, &table)==FAILURE) { + RETURN_FALSE; + } + id = php3_msql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); + break; + case 3: + if (getParameters(ht, 3, &db, &table, &msql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(msql_link); + id = msql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + msql = (int) php3_list_find(id,&type); + if (type!=MSQL_GLOBAL(php3_msql_module).le_link && type!=MSQL_GLOBAL(php3_msql_module).le_plink) { + php3_error(E_WARNING,"%d is not a mSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(db); + if (msqlSelectDB(msql,db->value.str.val)==-1) { + RETURN_FALSE; + } + convert_to_string(table); + if ((msql_result=msqlListFields(msql,table->value.str.val))==NULL) { + php3_error(E_WARNING,"Unable to save mSQL query result"); + RETURN_FALSE; + } + RETVAL_LONG(_new_query(msql_result, 0)); +} +/* }}} */ + +/* {{{ proto string msql_error([int link_identifier]) + Returns the text of the error message from previous mSQL operation */ +void php3_msql_error(INTERNAL_FUNCTION_PARAMETERS) +{ + if (ARG_COUNT(ht)) { + WRONG_PARAM_COUNT; + } + RETURN_STRING(msqlErrMsg,1); +} +/* }}} */ + +/* {{{ proto int msql_result(int query, int row [, mixed field]) + Get result data */ +DLEXPORT void php3_msql_result(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result, *row, *field=NULL; + m_result *msql_result; + m_query *msql_query; + m_row sql_row; + int type,field_offset=0; + MSQL_TLS_VARS; + PLS_FETCH(); + + switch (ARG_COUNT(ht)) { + case 2: + if (getParameters(ht, 2, &result, &row)==FAILURE) { + RETURN_FALSE; + } + break; + case 3: + if (getParameters(ht, 3, &result, &row, &field)==FAILURE) { + RETURN_FALSE; + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + + MSQL_GET_QUERY(result); + + convert_to_long(row); + if (row->value.lval<0 || row->value.lval>=msqlNumRows(msql_result)) { + php3_error(E_WARNING,"Unable to jump to row %d on mSQL query index %d",row->value.lval,result->value.lval); + RETURN_FALSE; + } + msqlDataSeek(msql_result,row->value.lval); + if ((sql_row=msqlFetchRow(msql_result))==NULL) { /* shouldn't happen? */ + RETURN_FALSE; + } + + if (field) { + switch(field->type) { + case IS_STRING: { + int i=0; + m_field *tmp_field; + char *table_name,*field_name,*tmp; + + if ((tmp=strchr(field->value.str.val,'.'))) { + *tmp = 0; + table_name = estrdup(field->value.str.val); + field_name = estrdup(tmp+1); + } else { + table_name = NULL; + field_name = estrndup(field->value.str.val,field->value.str.len); + } + msqlFieldSeek(msql_result,0); + while ((tmp_field=msqlFetchField(msql_result))) { + if ((!table_name || !strcasecmp(tmp_field->table,table_name)) && !strcasecmp(tmp_field->name,field_name)) { + field_offset = i; + break; + } + i++; + } + if (!tmp_field) { /* no match found */ + php3_error(E_WARNING,"%s%s%s not found in mSQL query index %d", + (table_name?table_name:""), (table_name?".":""), field_name, result->value.lval); + efree(field_name); + if (table_name) { + efree(table_name); + } + RETURN_FALSE; + } + efree(field_name); + if (table_name) { + efree(table_name); + } + } + break; + default: + convert_to_long(field); + field_offset = field->value.lval; + if (field_offset<0 || field_offset>=msqlNumFields(msql_result)) { + php3_error(E_WARNING,"Bad column offset specified"); + RETURN_FALSE; + } + break; + } + } + + if (sql_row[field_offset]) { + if (PG(magic_quotes_runtime)) { + return_value->value.str.val = _php3_addslashes(sql_row[field_offset],0,&return_value->value.str.len,0); + } else { + return_value->value.str.len = (sql_row[field_offset]?strlen(sql_row[field_offset]):0); + return_value->value.str.val = (char *) safe_estrndup(sql_row[field_offset],return_value->value.str.len); + } + } else { + var_reset(return_value); + } + + return_value->type = IS_STRING; +} +/* }}} */ + +/* {{{ proto int msql_num_rows(int query) + Get number of rows in a result */ +DLEXPORT void php3_msql_num_rows(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + m_result *msql_result; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + RETVAL_LONG(msql_result ? msqlNumRows(msql_result) : 0); +} +/* }}} */ + +/* {{{ proto int msql_num_fields(int query) + Get number of fields in a result */ +DLEXPORT void php3_msql_num_fields(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + m_result *msql_result; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + RETVAL_LONG(msql_result ? msqlNumFields(msql_result) : 0); +} +/* }}} */ + +/* {{{ proto array msql_fetch_row(int query) + Get a result row as an enumerated array */ +DLEXPORT void php3_msql_fetch_row(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + m_result *msql_result; + m_row msql_row; + m_query *msql_query; + int type; + int num_fields; + int i; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + if (!msql_result || + ((msql_row = msqlFetchRow(msql_result)) == NULL) || + (array_init(return_value)==FAILURE)) { + RETURN_FALSE; + } + num_fields = msqlNumFields(msql_result); + + for (i=0; ivalue.ht, msql_field->name, strlen(msql_field->name)+1, pval_ptr); + } +} + +/* {{{ proto object msql_fetch_object(int query) + Fetch a result row as an object */ +DLEXPORT void php3_msql_fetch_object(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU); + if (return_value->type==IS_ARRAY) { + return_value->type=IS_OBJECT; + } +} +/* }}} */ + +/* {{{ proto array msql_fetch_array(int query) + Fetch a result row as an associative array */ +DLEXPORT void php3_msql_fetch_array(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto int msql_data_seek(int query, int row_number) + Move internal result pointer */ +DLEXPORT void php3_msql_data_seek(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result,*offset; + m_result *msql_result; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &offset)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + convert_to_long(offset); + if (!msql_result || + offset->value.lval<0 || + offset->value.lval>=msqlNumRows(msql_result)) { + php3_error(E_WARNING,"Offset %d is invalid for mSQL query index %d",offset->value.lval,result->value.lval); + RETURN_FALSE; + } + msqlDataSeek(msql_result,offset->value.lval); + RETURN_TRUE; +} +/* }}} */ + +static char *php3_msql_get_field_name(int field_type) +{ + switch (field_type) { +#if MSQL1 + case INT_TYPE: + return "int"; + break; + case CHAR_TYPE: + return "char"; + break; + case REAL_TYPE: + return "real"; + break; + case IDENT_TYPE: + return "ident"; + break; + case NULL_TYPE: + return "null"; + break; +#else + case INT_TYPE: + case UINT_TYPE: + case CHAR_TYPE: + case TEXT_TYPE: + case REAL_TYPE: + case NULL_TYPE: + case DATE_TYPE: + case TIME_TYPE: + case MONEY_TYPE: + return msqlTypeNames[field_type]; + break; +#endif + default: + return "unknown"; + break; + } +} + +/* {{{ proto object msql_fetch_field(int query [, int field_offset]) + Get column information from a result and return as an object */ +DLEXPORT void php3_msql_fetch_field(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result, *field=NULL; + m_result *msql_result; + m_field *msql_field; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + switch (ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &result)==FAILURE) { + RETURN_FALSE; + } + break; + case 2: + if (getParameters(ht, 2, &result, &field)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(field); + default: + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + + if (field) { + if (field->value.lval<0 || field->value.lval>=msqlNumRows(msql_result)) { + php3_error(E_NOTICE,"mSQL: Bad field offset specified"); + RETURN_FALSE; + } + msqlFieldSeek(msql_result,field->value.lval); + } + if (!msql_result || (msql_field=msqlFetchField(msql_result))==NULL) { + RETURN_FALSE; + } + if (object_init(return_value)==FAILURE) { + RETURN_FALSE; + } + + add_property_string(return_value, "name",(msql_field->name?msql_field->name:empty_string), 1); + add_property_string(return_value, "table",(msql_field->table?msql_field->table:empty_string), 1); + add_property_long(return_value, "not_null",IS_NOT_NULL(msql_field->flags)); +#if MSQL1 + add_property_long(return_value, "primary_key",(msql_field->flags&PRI_KEY_FLAG?1:0)); +#else + add_property_long(return_value, "unique",(msql_field->flags&UNIQUE_FLAG?1:0)); +#endif + + add_property_string(return_value, "type",php3_msql_get_field_name(msql_field->type), 1); +} +/* }}} */ + +/* {{{ proto int msql_field_seek(int query, int field_offset) + Set result pointer to a specific field offset */ +DLEXPORT void php3_msql_field_seek(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result, *offset; + m_result *msql_result; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &offset)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + convert_to_long(offset); + if(!msql_result) { + RETURN_FALSE; + } + if (offset->value.lval<0 || offset->value.lval>=msqlNumFields(msql_result)) { + php3_error(E_WARNING,"Field %d is invalid for mSQL query index %d", + offset->value.lval,result->value.lval); + RETURN_FALSE; + } + msqlFieldSeek(msql_result,offset->value.lval); + RETURN_TRUE; +} +/* }}} */ + +#define PHP3_MSQL_FIELD_NAME 1 +#define PHP3_MSQL_FIELD_TABLE 2 +#define PHP3_MSQL_FIELD_LEN 3 +#define PHP3_MSQL_FIELD_TYPE 4 +#define PHP3_MSQL_FIELD_FLAGS 5 + +static void php3_msql_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) +{ + pval *result, *field; + m_result *msql_result; + m_field *msql_field; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &field)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + if(!msql_result) { + RETURN_FALSE; + } + convert_to_long(field); + if (field->value.lval<0 || field->value.lval>=msqlNumFields(msql_result)) { + php3_error(E_WARNING,"Field %d is invalid for mSQL query index %d",field->value.lval,result->value.lval); + RETURN_FALSE; + } + msqlFieldSeek(msql_result,field->value.lval); + if ((msql_field=msqlFetchField(msql_result))==NULL) { + RETURN_FALSE; + } + + switch (entry_type) { + case PHP3_MSQL_FIELD_NAME: + return_value->value.str.len = strlen(msql_field->name); + return_value->value.str.val = estrndup(msql_field->name,return_value->value.str.len); + return_value->type = IS_STRING; + break; + case PHP3_MSQL_FIELD_TABLE: + return_value->value.str.len = strlen(msql_field->table); + return_value->value.str.val = estrndup(msql_field->table,return_value->value.str.len); + return_value->type = IS_STRING; + break; + case PHP3_MSQL_FIELD_LEN: + return_value->value.lval = msql_field->length; + return_value->type = IS_LONG; + break; + case PHP3_MSQL_FIELD_TYPE: + return_value->value.str.val = estrdup(php3_msql_get_field_name(msql_field->type)); + return_value->value.str.len = strlen(return_value->value.str.val); + return_value->type = IS_STRING; + break; + case PHP3_MSQL_FIELD_FLAGS: +#if MSQL1 + if ((msql_field->flags&NOT_NULL_FLAG) && (msql_field->flags&PRI_KEY_FLAG)) { + return_value->value.str.val = estrndup("primary key not null",20); + return_value->value.str.len = 20; + return_value->type = IS_STRING; + } else if (msql_field->flags&NOT_NULL_FLAG) { + return_value->value.str.val = estrndup("not null",8); + return_value->value.str.len = 8; + return_value->type = IS_STRING; + } else if (msql_field->flags&PRI_KEY_FLAG) { + return_value->value.str.val = estrndup("primary key",11); + return_value->value.str.len = 11; + return_value->type = IS_STRING; + } else { + var_reset(return_value); + } +#else + if ((msql_field->flags&NOT_NULL_FLAG) && (msql_field->flags&UNIQUE_FLAG)) { + return_value->value.str.val = estrndup("unique not null",15); + return_value->value.str.len = 15; + return_value->type = IS_STRING; + } else if (msql_field->flags&NOT_NULL_FLAG) { + return_value->value.str.val = estrndup("not null",8); + return_value->value.str.len = 8; + return_value->type = IS_STRING; + } else if (msql_field->flags&UNIQUE_FLAG) { + return_value->value.str.val = estrndup("unique",6); + return_value->value.str.len = 6; + return_value->type = IS_STRING; + } else { + var_reset(return_value); + } +#endif + break; + default: + RETURN_FALSE; + } +} + +/* {{{ proto string msql_field_name(int query, int field_index) + Get the name of the specified field in a result */ +DLEXPORT void php3_msql_field_name(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_MSQL_FIELD_NAME); +} +/* }}} */ + +/* {{{ proto string msql_field_table(int query, int field_offset) + Get name of the table the specified field is in */ +DLEXPORT void php3_msql_field_table(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_MSQL_FIELD_TABLE); +} +/* }}} */ + +/* {{{ proto int msql_field_len(int query, int field_offet) + Returns the length of the specified field */ +DLEXPORT void php3_msql_field_len(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_MSQL_FIELD_LEN); +} +/* }}} */ + +/* {{{ proto string msql_field_type(int query, int field_offset) + Get the type of the specified field in a result */ +DLEXPORT void php3_msql_field_type(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_MSQL_FIELD_TYPE); +} +/* }}} */ + +/* {{{ proto string msql_field_flags(int query, int field_offset) + Get the flags associated with the specified field in a result */ +DLEXPORT void php3_msql_field_flags(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_msql_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_MSQL_FIELD_FLAGS); +} +/* }}} */ + + +/* {{{ proto int msql_free_result(int query) + Free result memory */ +DLEXPORT void php3_msql_free_result(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + m_result *msql_result; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + MSQL_GET_QUERY(result); + php3_list_delete(result->value.lval); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int msql_affected_rows(int query) + Return number of affected rows */ +DLEXPORT void php3_msql_affected_rows(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + m_result *msql_result; + m_query *msql_query; + int type; + MSQL_TLS_VARS; + + if(ARG_COUNT(ht) != 1 || getParameters(ht, 1, &result) == FAILURE) { + WRONG_PARAM_COUNT; + } + MSQL_GET_QUERY(result); + RETVAL_LONG(msql_query->af_rows); +} +/* }}} */ + +#endif + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + diff --git a/ext/msql/php3_msql.h b/ext/msql/php3_msql.h new file mode 100644 index 00000000000..6c1e8e3fbf3 --- /dev/null +++ b/ext/msql/php3_msql.h @@ -0,0 +1,100 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997,1998 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Zeev Suraski | + +----------------------------------------------------------------------+ + */ + + +/* $Id$ */ + +#ifndef _PHP3_MSQL_H +#define _PHP3_MSQL_H + +#if COMPILE_DL +#undef HAVE_MSQL +#define HAVE_MSQL 1 +#define php3_minit_msql dl_init +#endif + +#if HAVE_MSQL + +extern php3_module_entry msql_module_entry; +#define msql_module_ptr &msql_module_entry + +/* mSQL functions */ +extern DLEXPORT int php3_minit_msql(INIT_FUNC_ARGS); +extern DLEXPORT int php3_rinit_msql(INIT_FUNC_ARGS); +extern DLEXPORT int php3_mshutdown_msql(SHUTDOWN_FUNC_ARGS); +extern DLEXPORT void php3_info_msql(void); +extern DLEXPORT void php3_msql_connect(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_pconnect(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_close(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_select_db(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_create_db(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_drop_db(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_list_dbs(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_list_tables(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_list_fields(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_error(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_affected_rows(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_query(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_db_query(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_result(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_num_rows(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_num_fields(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_fetch_row(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_data_seek(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_fetch_field(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_field_seek(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_free_result(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_field_name(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_field_table(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_field_len(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_field_type(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_field_flags(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_fetch_array(INTERNAL_FUNCTION_PARAMETERS); +extern DLEXPORT void php3_msql_fetch_object(INTERNAL_FUNCTION_PARAMETERS); + +typedef struct { + long default_link; + long num_links,num_persistent; + long max_links,max_persistent; + long allow_persistent; + int le_query; + int le_link; + int le_plink; +} msql_module; + +#ifndef THREAD_SAFE +extern msql_module php3_msql_module; +#endif +#else + +#define msql_module_ptr NULL + +#endif + +#endif /* _PHP3_MSQL_H */ diff --git a/ext/msql/setup.stub b/ext/msql/setup.stub new file mode 100644 index 00000000000..cced055d905 --- /dev/null +++ b/ext/msql/setup.stub @@ -0,0 +1,11 @@ +# $Source$ +# $Id$ + +define_option with-msql 'mSQL support?' yesnodir \ + 'no /usr/local/Hughes mSQL install' \ +' Whether to build PHP with mSQL support. PHP supports both mSQL 1.0 and\n + mSQL 2.0. However, if you build PHP with mSQL 1.0 libraries, you will\n + only be able to access mSQL 1.0 databases, ditto for mSQL 2.0.\n + More info about mSQL can be found at http://www.hughes.com.au/.' + + diff --git a/ext/mysql/setup.stub b/ext/mysql/setup.stub index 5297b000823..77b560c6cdd 100644 --- a/ext/mysql/setup.stub +++ b/ext/mysql/setup.stub @@ -1,6 +1,7 @@ +# $Source$ # $Id$ -define_option with-mysql 'mysql support?' yesnodir \ - "defs" \ -' Whether to include mysql support.' - +define_option with-mysql 'MySQL support?' yesnodir \ + 'no /usr/local MySQL install' \ +' Whether to build PHP with MySQL support.\n + More info about MySQL can be found at http://www.mysql.com/.' diff --git a/ext/oracle/Makefile.am b/ext/oracle/Makefile.am new file mode 100644 index 00000000000..65c47ceff1e --- /dev/null +++ b/ext/oracle/Makefile.am @@ -0,0 +1,5 @@ +# $Id$ + +INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend +noinst_LIBRARIES=libphpext_oracle.a +libphpext_oracle_a_SOURCES=oracle.c oci8.c diff --git a/ext/oracle/config.h.stub b/ext/oracle/config.h.stub new file mode 100644 index 00000000000..7484b10b2ca --- /dev/null +++ b/ext/oracle/config.h.stub @@ -0,0 +1,6 @@ +/* Define if you have the Oracle database client libraries */ +#define HAVE_ORACLE 0 + +/* Define if you have the Oracle version 8 database client libraries */ +#define HAVE_OCI8 0 + diff --git a/ext/oracle/config.m4 b/ext/oracle/config.m4 new file mode 100644 index 00000000000..1deec69bfe7 --- /dev/null +++ b/ext/oracle/config.m4 @@ -0,0 +1,162 @@ +dnl $Id$ + +AC_DEFUN(AC_ORACLE_VERSION,[ + AC_MSG_CHECKING([Oracle version]) + if test -f "$ORACLEINST_TOP/orainst/unix.rgs" + then + ORACLE_VERSION=`grep '"ocommon"' $ORACLEINST_TOP/orainst/unix.rgs | sed 's/[ ][ ]*/:/g' | cut -d: -f 6 | cut -c 2-4` + test -z "$ORACLE_VERSION" && ORACLE_VERSION=7.3 + else + ORACLE_VERSION=8.0 + fi + AC_MSG_RESULT($ORACLE_VERSION) +]) + +AC_MSG_CHECKING(for Oracle support) +AC_ARG_WITH(oracle, +[ --with-oracle[=DIR] Include Oracle database support. DIR is Oracle's + home directory, defaults to \$ORACLE_HOME.], +[ + case "$withval" in + yes) + ORACLEINST_TOP=$ORACLE_HOME + AC_MSG_RESULT(yes) + PHP_EXTENSION(oracle) + ;; + no) + ORACLEINST_TOP= + AC_MSG_RESULT(no) + ;; + *) + ORACLEINST_TOP=$withval + AC_MSG_RESULT(yes) + PHP_EXTENSION(oracle) + ;; + esac + + if test "$ORACLEINST_TOP" != "" + then + + # Oracle include files + + if test -f "$ORACLEINST_TOP/rdbms/public/ocidfn.h" + then + # V8.0.5 + ORACLE_INCLUDE="$ORACLE_INCLUDE -I$ORACLEINST_TOP/rdbms/public" + elif test -f "$ORACLEINST_TOP/rdbms/demo/ocidfn.h" + then + # V7.[0123] + ORACLE_INCLUDE=-I$ORACLEINST_TOP/rdbms/demo + fi + + if test -d "$ORACLEINST_TOP/network/public" + then + # V8 + ORACLE_INCLUDE="$ORACLE_INCLUDE -I$ORACLEINST_TOP/network/public" + fi + + if test -d "$ORACLEINST_TOP/plsql/public" + then + # V8 + ORACLE_INCLUDE="$ORACLE_INCLUDE -I$ORACLEINST_TOP/plsql/public" + fi + + # Need to know the version, otherwhise we will mixup nlsrtl + AC_ORACLE_VERSION($ORACLEINST_TOP) + + # Oracle libs - nightmare :-) + + ORACLE_LIBDIR=lib + ORACLE_LFLAGS="-L$ORACLEINST_TOP/$ORACLE_LIBDIR ${ld_runpath_switch}$ORACLEINST_TOP/$ORACLE_LIBDIR" + if test -f "$ORACLEINST_TOP/rdbms/lib/sysliblist" + then + ORA_SYSLIB="`cat $ORACLEINST_TOP/rdbms/lib/sysliblist`" + else + ORA_SYSLIB="-lm" + fi + + # Oracle Static libs + case $ORACLE_VERSION in + 7.0|7.1) + ORACLE_STLIBS="-locic $ORACLEINST_TOP/$ORACLE_LIBDIR/osntab.o \ + -lsqlnet -lora -lsqlnet -lnlsrtl -lcv6 -lcore -lnlsrtl -lcv6 \ + -lcore $ORA_SYSLIB -lcore $ORA_SYSLIB" + if test "`uname -s 2>/dev/null`" = "AIX"; then + ORACLE_STLIBS="$ORACLE_STLIBS -bI:$ORACLE_HOME/lib/mili.exp" + fi + ;; + 7.2) + ORACLE_STLIBS="-locic $ORACLEINST_TOP/$ORACLE_LIBDIR/osntab.o \ + -lsqlnet -lora -lsqlnet -lora -lnlsrtl3 -lc3v6 -lcore3 -lnlsrtl3 \ + -lcore3 $ORA_SYSLIB -lcore3 $ORA_SYSLIB" + ;; + 7.3) + ORACLE_STLIBS="-lclient -lsqlnet -lncr -lsqlnet -lclient -lcommon \ + -lgeneric -lsqlnet -lncr -lsqlnet -lclient -lcommon -lgeneric \ + -lepc -lnlsrtl3 -lc3v6 -lcore3 -lnlsrtl3 -lcore3 -lnlsrtl3 \ + $ORA_SYSLIB -lcore3 $ORA_SYSLIB" + ;; + 8.0) + ORACLE_STLIBS="-lclient -lsqlnet -lncr -lsqlnet -lclient -lcommon \ + -lgeneric -lsqlnet -lncr -lsqlnet -lclient -lcommon -lgeneric \ + -lepc -lnlsrtl3 -lc3v6 -lcore4 -lnlsrtl3 -lcore4 -lnlsrtl3 \ + $ORA_SYSLIB -lcore3 $ORA_SYSLIB" + ;; + *) + ORACLE_STLIBS= + ;; + esac + + # Oracle shared libs + case $ORACLE_VERSION in + 7.0) + # shared libs not supported + ORACLE_SHLIBS="$ORACLE_STLIBS" + ;; + 7.1) + if test -f $ORACLEINST_TOP/$ORACLE_LIBDIR/liboracle.s? + then + ORACLE_SHLIBS="-loracle $ORA_SYSLIB" + else + ORACLE_SHLIBS="$ORACLE_STLIBS" + fi + ;; + 7.2|7.3) + if test -f $ORACLEINST_TOP/$ORACLE_LIBDIR/libclntsh.s? + then + ORACLE_SHLIBS="-lclntsh $ORA_SYSLIB" + else + ORACLE_SHLIBS="$ORACLE_STLIBS" + fi + ;; + 8.0) + if test -f $ORACLEINST_TOP/$ORACLE_LIBDIR/libclntsh.s? -o \ + -f $ORACLEINST_TOP/$ORACLE_LIBDIR/libclntsh.a # AIX + then + if test "$CC" = "gcc" -a "`uname -sv`" = "AIX 4"; then + # for Oracle 8 on AIX 4 + ORA_SYSLIB="$ORA_SYSLIB -nostdlib /lib/crt0_r.o /usr/lib/libpthreads.a /usr/lib/libc_r.a -lgcc" + fi + ORACLE_SHLIBS="-lclntsh -lpsa -lcore4 -lnlsrtl3 -lclntsh $ORA_SYSLIB" + else + ORACLE_SHLIBS="$ORACLE_STLIBS" + fi + AC_DEFINE(HAVE_OCI8) + ;; + *) + ORACLE_SHLIBS= + ;; + esac + + # only using shared libs right now + ORACLE_LIBS=$ORACLE_SHLIBS + + AC_DEFINE(HAVE_ORACLE) + + fi + +],[AC_MSG_RESULT(no)]) +EXTRA_LIBS="$EXTRA_LIBS $ORACLE_SHLIBS $ORACLE_STLIBS $ORACLE_LIBS $ORACLE_LFLAGS" +INCLUDES="$INCLUDES $ORACLE_INCLUDE" +AC_SUBST(ORACLE_HOME) +AC_SUBST(ORACLE_VERSION) diff --git a/ext/oracle/oci8.c b/ext/oracle/oci8.c new file mode 100644 index 00000000000..8ef517219c4 --- /dev/null +++ b/ext/oracle/oci8.c @@ -0,0 +1,3172 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-1999 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Stig Sæther Bakken | + | Thies C. Arntzen | + | | + | Initial work sponsored by | + | Digital Collections, http://www.digicol.de/ | + +----------------------------------------------------------------------+ + */ + +#define OCI8_USE_EMALLOC 0 /* set this to 1 if you want to use the php memory manager! */ + +/* $Id$ */ + +/* TODO list: + * + * - Error mode (print or shut up?) + * - returning refcursors as statement handles + * - OCIPasswordChange() + * - Prefetching control + * - LONG, LONG RAW, RAW is now limited to 2MB (should be user-settable); + * - binding of arrays + * - Truncate input values to the bind size + * - Character sets for NCLOBS + * - piecewise operation for longs, lobs etc + * - split the module into an upper (php-callable) and lower (c-callable) layer! + * - make_pval needs some cleanup.... + * - persistend connections + * - NULLS (retcode/indicator) needs some more work for describing & binding + * - remove all XXXs + * - clean up and documentation + * - OCINewContext function. + * - there seems to be a bug in OCI where it returns ORA-01406 (value truncated) - whereby it isn't (search for 01406 in the source) + * this seems to happen for NUMBER values only... + * - make OCIInternalDebug accept a mask of flags.... + * - better NULL handling + * - add some flags to OCIFetchStatement (maxrows etc...) + */ + +/* {{{ includes & stuff */ + +#if defined(COMPILE_DL) +# ifdef THREAD_SAFE +# undef THREAD_SAFE /* XXX no need in 3.0 */ +# endif +# include "dl/phpdl.h" +#endif + +#include "php.h" +/*#include "internal_functions.h"*/ +#include "php3_oci8.h" + +#if HAVE_OCI8 + +#define SAFE_STRING(s) ((s)?(s):"") + +/*#include "php3_list.h"*/ +#if !(WIN32|WINNT) +# include "build-defs.h" +#endif +#include "snprintf.h" +#include "head.h" + +/* }}} */ +/* {{{ thread safety stuff */ + +#ifdef THREAD_SAFE +# define OCI8_GLOBAL(a) oci8_globals->a +# define OCI8_TLS_VARS oci8_global_struct *oci8_globals = TlsGetValue(OCI8Tls); +void *oci8_mutex; +DWORD OCI8Tls; +static int numthreads=0; + +typedef struct oci8_global_struct { + oci8_module php3_oci8_module; +} oci8_global_struct; +#else /* !defined(THREAD_SAFE) */ +# define OCI8_GLOBAL(a) a +# define OCI8_TLS_VARS +oci8_module php3_oci8_module; +#endif /* defined(THREAD_SAFE) */ + +/* }}} */ +/* {{{ dynamically loadable module stuff */ + +#if COMPILE_DL +DLEXPORT php3_module_entry *get_module() { return &oci8_module_entry; }; + +# if (WIN32|WINNT) && defined(THREAD_SAFE) +/* NOTE: You should have an oci8.def file where you export DllMain */ +BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, + LPVOID lpReserved) +{ + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + if ((OCI8Tls = TlsAlloc()) == 0xFFFFFFFF){ + return 0; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + if (!TlsFree(OCI8Tls)) { + return 0; + } + break; + } + return 1; +} + +# endif /* thread safe on Windows */ +#endif /* COMPILE_DL */ + +/* }}} */ +/* {{{ startup/shutdown/info/internal function prototypes */ + +int php3_minit_oci8(INIT_FUNC_ARGS); +int php3_rinit_oci8(INIT_FUNC_ARGS); +int php3_mshutdown_oci8(SHUTDOWN_FUNC_ARGS); +int php3_rshutdown_oci8(SHUTDOWN_FUNC_ARGS); +void php3_info_oci8(void); + +static ub4 oci8_error(OCIError *err_p, char *what, sword status); +/* static int oci8_ping(oci8_connection *conn); XXX NYI */ +static void oci8_debug(const char *format,...); + +static void _oci8_close_conn(oci8_connection *connection); +static void _oci8_free_stmt(oci8_statement *statement); +static void _oci8_free_column(oci8_out_column *column); +static void _oci8_detach(oci8_server *server); +static void _oci8_logoff(oci8_session *session); +static void _oci8_free_descr(oci8_descriptor *descr); + +static oci8_connection *oci8_get_conn(int, const char *, HashTable *, HashTable *); +static oci8_statement *oci8_get_stmt(int, const char *, HashTable *); +static oci8_out_column *oci8_get_col(oci8_statement *, int, pval *, char *); + +static int oci8_make_pval(pval *,int,oci8_out_column *, char *,HashTable *, int mode); +static int oci8_parse(oci8_connection *, text *, ub4, HashTable *); +static int oci8_execute(oci8_statement *, char *,ub4 mode); +static int oci8_fetch(oci8_statement *, ub4, char *); +static ub4 oci8_loaddesc(oci8_connection *, oci8_descriptor *, char **); + +static void oci8_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent); +static oci8_server *oci8_attach(char *dbname,int persistent,HashTable *list, HashTable *plist); +static oci8_session *oci8_login(oci8_server* server,char *username,char *password,int persistent,HashTable *list, HashTable *plist); + + +/* bind callback functions */ +static sb4 oci8_bind_in_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 *, ub1 *, dvoid **); +static sb4 oci8_bind_out_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 **, ub1 *, dvoid **, ub2 **); + +/* define callback function */ +static sb4 oci8_define_callback(dvoid *, OCIDefine *, ub4, dvoid **, ub4 **, ub1 *, dvoid **, ub2 **); + +/* }}} */ +/* {{{ extension function prototypes */ + +void php3_oci8_bindbyname(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_definebyname(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_columnisnull(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_columnname(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_columnsize(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_columntype(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_execute(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_fetch(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_fetchinto(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_fetchstatement(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_freestatement(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_internaldebug(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_logoff(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_logon(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_plogon(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_error(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_freedesc(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_savedesc(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_loaddesc(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_commit(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_rollback(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_newdescriptor(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_numcols(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_parse(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_result(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_serverversion(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_statementtype(INTERNAL_FUNCTION_PARAMETERS); +void php3_oci8_rowcount(INTERNAL_FUNCTION_PARAMETERS); + +/* }}} */ +/* {{{ extension definition structures */ + +#define OCI_ASSOC 1<<0 +#define OCI_NUM 1<<1 +#define OCI_BOTH (OCI_ASSOC|OCI_NUM) + +#define OCI_RETURN_NULLS 1<<2 +#define OCI_RETURN_LOBS 1<<3 + +static unsigned char a3_arg_force_ref[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE }; +static unsigned char a2_arg_force_ref[] = { 2, BYREF_NONE, BYREF_FORCE }; + +function_entry oci8_functions[] = { + {"ocidefinebyname", php3_oci8_definebyname, a3_arg_force_ref}, + {"ocibindbyname", php3_oci8_bindbyname, a3_arg_force_ref}, + {"ocicolumnisnull", php3_oci8_columnisnull, NULL}, + {"ocicolumnname", php3_oci8_columnname, NULL}, + {"ocicolumnsize", php3_oci8_columnsize, NULL}, + {"ocicolumntype", php3_oci8_columntype, NULL}, + {"ociexecute", php3_oci8_execute, NULL}, + {"ocifetch", php3_oci8_fetch, NULL}, + {"ocifetchinto", php3_oci8_fetchinto, a2_arg_force_ref}, + {"ocifetchstatement",php3_oci8_fetchstatement,a2_arg_force_ref}, + {"ocifreestatement", php3_oci8_freestatement, NULL}, + {"ociinternaldebug", php3_oci8_internaldebug, NULL}, + {"ocinumcols", php3_oci8_numcols, NULL}, + {"ociparse", php3_oci8_parse, NULL}, + {"ociresult", php3_oci8_result, NULL}, + {"ociserverversion", php3_oci8_serverversion, NULL}, + {"ocistatementtype", php3_oci8_statementtype, NULL}, + {"ocirowcount", php3_oci8_rowcount, NULL}, + {"ocilogoff", php3_oci8_logoff, NULL}, + {"ocilogon", php3_oci8_logon, NULL}, + {"ociplogon", php3_oci8_plogon, NULL}, + {"ocierror", php3_oci8_error, NULL}, + {"ocifreedescriptor",php3_oci8_freedesc, NULL}, + {"ocisavedesc", php3_oci8_savedesc, NULL}, + {"ociloaddesc", php3_oci8_loaddesc, NULL}, + {"ocicommit", php3_oci8_commit, NULL}, + {"ocirollback", php3_oci8_rollback, NULL}, + {"ocinewdescriptor", php3_oci8_newdescriptor, NULL}, + {NULL, NULL, NULL} +}; + +php3_module_entry oci8_module_entry = { + "OCI8", /* extension name */ + oci8_functions, /* extension function list */ + php3_minit_oci8, /* extension-wide startup function */ + php3_mshutdown_oci8, /* extension-wide shutdown function */ + php3_rinit_oci8, /* per-request startup function */ + php3_rshutdown_oci8, /* per-request shutdown function */ + php3_info_oci8, /* information function */ + STANDARD_MODULE_PROPERTIES +}; + +/* }}} */ +/* {{{ startup, shutdown and info functions */ + +int php3_minit_oci8(INIT_FUNC_ARGS) +{ +#ifdef THREAD_SAFE + oci8_global_struct *oci8_globals; +# if !COMPILE_DL +# if WIN32|WINNT + CREATE_MUTEX(oci8_mutex,"OCI8_TLS"); +# endif + SET_MUTEX(oci8_mutex); + numthreads++; + if (numthreads == 1) { + if ((OCI8Tls = TlsAlloc()) == 0xFFFFFFFF){ + FREE_MUTEX(oci8_mutex); + return 0; + } + } + FREE_MUTEX(oci8_mutex); +# endif /* !COMPILE_DL */ + oci8_globals = + (oci8_global_struct *) LocalAlloc(LPTR, sizeof(oci8_global_struct)); + TlsSetValue(OCI8Tls, (void *) oci8_globals); +#endif /* THREAD_SAFE */ + + if (cfg_get_long("oci8.allow_persistent", + &OCI8_GLOBAL(php3_oci8_module).allow_persistent) + == FAILURE) { + OCI8_GLOBAL(php3_oci8_module).allow_persistent = -1; + } + if (cfg_get_long("oci8.max_persistent", + &OCI8_GLOBAL(php3_oci8_module).max_persistent) + == FAILURE) { + OCI8_GLOBAL(php3_oci8_module).max_persistent = -1; + } + if (cfg_get_long("oci8.max_links", + &OCI8_GLOBAL(php3_oci8_module).max_links) + == FAILURE) { + OCI8_GLOBAL(php3_oci8_module).max_links = -1; + } + + OCI8_GLOBAL(php3_oci8_module).num_persistent = 0; + + OCI8_GLOBAL(php3_oci8_module).le_conn = + register_list_destructors(_oci8_close_conn, NULL); + + OCI8_GLOBAL(php3_oci8_module).le_stmt = + register_list_destructors(_oci8_free_stmt, NULL); + + OCI8_GLOBAL(php3_oci8_module).le_server = + register_list_destructors(_oci8_detach, NULL); + + OCI8_GLOBAL(php3_oci8_module).le_pserver = + register_list_destructors(_oci8_detach, NULL); + + OCI8_GLOBAL(php3_oci8_module).le_session = + register_list_destructors(_oci8_logoff, NULL); + + OCI8_GLOBAL(php3_oci8_module).le_psession = + register_list_destructors(_oci8_logoff, NULL); + + + if (cfg_get_long("oci8.debug_mode", + &OCI8_GLOBAL(php3_oci8_module).debug_mode) == FAILURE) { + OCI8_GLOBAL(php3_oci8_module).debug_mode = 0; + } + +/* thies@digicol.de 990203 i do not think that we will need all of them - just in here for completeness for now! */ + REGISTER_LONG_CONSTANT("OCI_DEFAULT",OCI_DEFAULT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_DESCRIBE_ONLY",OCI_DESCRIBE_ONLY, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_COMMIT_ON_SUCCESS",OCI_COMMIT_ON_SUCCESS, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_EXACT_FETCH",OCI_EXACT_FETCH, CONST_CS | CONST_PERSISTENT); + +/* for OCIBindByName (real "oci" names + short "php" names*/ + REGISTER_LONG_CONSTANT("SQLT_BFILEE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("OCI_B_BFILE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_B_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_B_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_B_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_B_ROWID",SQLT_RDD, CONST_CS | CONST_PERSISTENT); + +/* for OCIFetchInto & OCIResult */ + REGISTER_LONG_CONSTANT("OCI_ASSOC",OCI_ASSOC, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_NUM",OCI_NUM, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_BOTH",OCI_BOTH, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT); + +/* for OCINewDescriptor (real "oci" names + short "php" names*/ + REGISTER_LONG_CONSTANT("OCI_DTYPE_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_DTYPE_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_DTYPE_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("OCI_D_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_D_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OCI_D_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT); + +#if OCI8_USE_EMALLOC + OCIInitialize(OCI_DEFAULT, (dvoid *)connection, ocimalloc, ocirealloc, ocifree); +#else + OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL); +#endif + + OCIEnvInit(&OCI8_GLOBAL(php3_oci8_module).pEnv, OCI_DEFAULT, 0, NULL); + + return SUCCESS; +} + +/* ----------------------------------------------------------------- */ + + +int php3_rinit_oci8(INIT_FUNC_ARGS) +{ + OCI8_TLS_VARS; + + OCI8_GLOBAL(php3_oci8_module).num_links = + OCI8_GLOBAL(php3_oci8_module).num_persistent; + + OCI8_GLOBAL(php3_oci8_module).debug_mode = 0; /* start "fresh" */ + + oci8_debug("php3_rinit_oci8"); + + return SUCCESS; +} + + +int php3_mshutdown_oci8(SHUTDOWN_FUNC_ARGS) +{ +#ifdef THREAD_SAFE + oci8_global_struct *oci8_globals; + oci8_globals = TlsGetValue(OCI8Tls); + if (oci8_globals != 0) { + LocalFree((HLOCAL) oci8_globals); + } +#if !COMPILE_DL + SET_MUTEX(oci8_mutex); + numthreads--; + if (!numthreads) { + if (!TlsFree(OCI8Tls)) { + FREE_MUTEX(oci8_mutex); + return 0; + } + } + FREE_MUTEX(oci8_mutex); +#endif +#endif + return SUCCESS; +} + + +int php3_rshutdown_oci8(SHUTDOWN_FUNC_ARGS) +{ + oci8_debug("php3_rshutdown_oci8"); + /* XXX free all statements, rollback all outstanding transactions */ + return SUCCESS; +} + + +void php3_info_oci8() +{ +#if !(WIN32|WINNT) + php3_printf("Oracle version: %s
\n" + "Compile-time ORACLE_HOME: %s
\n" + "Libraries used: %s", + PHP_ORACLE_VERSION, PHP_ORACLE_HOME, PHP_ORACLE_LIBS); +#endif +} + +/* }}} */ +/* {{{ debug malloc/realloc/free */ + +#if OCI8_USE_EMALLOC +CONST dvoid *ocimalloc(dvoid *ctx, size_t size) +{ + dvoid *ret; + ret = (dvoid *)emalloc(size); + oci8_debug("ocimalloc(%d) = %08x", size,ret); + return ret; +} + +CONST dvoid *ocirealloc(dvoid *ctx, dvoid *ptr, size_t size) +{ + dvoid *ret; + oci8_debug("ocirealloc(%08x, %d)", ptr, size); + ret = (dvoid *)erealloc(ptr, size); + return ptr; +} + +CONST void ocifree(dvoid *ctx, dvoid *ptr) +{ + oci8_debug("ocifree(%08x)", ptr); + efree(ptr); +} +#endif + +/* }}} */ +/* {{{ oci8_free_define() */ + +static int +oci8_free_define(oci8_define *define) +{ + oci8_debug("oci8_free_define: %s",define->name); + + if (define->name) { + efree(define->name); + define->name = 0; + } + return 0; +} + +/* }}} */ +/* {{{ _oci8_free_column() */ + +static void +_oci8_free_column(oci8_out_column *column) +{ + + if (! column) { + return; + } + + oci8_debug("_oci8_free_column: %s",column->name); + + if (column->data) { + if (column->is_descr) { + _php3_hash_index_del(column->statement->conn->descriptors,(int) column->data); + } else { + if (! column->define) { + efree(column->data); + } + } + } + + if (column->name) { + efree(column->name); + } + + /* efree(column); XXX php cleares this for us */ +} + +/* }}} */ +/* {{{ _oci8_free_stmt() */ + +static void +_oci8_free_stmt(oci8_statement *statement) +{ + OCI8_TLS_VARS; + + if (! statement) { + return; + } + + oci8_debug("_oci8_free_stmt: id=%d last_query=\"%s\" conn=%d", + statement->id, + (statement->last_query?(char*)statement->last_query:"???"), + statement->conn->id); + + if (statement->pStmt) { + OCIHandleFree(statement->pStmt, OCI_HTYPE_STMT); + statement->pStmt = 0; + } + + if (statement->pError) { + OCIHandleFree(statement->pError, OCI_HTYPE_ERROR); + statement->pError = 0; + } + + if (statement->last_query) { + efree(statement->last_query); + } + + if (statement->columns) { + _php3_hash_destroy(statement->columns); + efree(statement->columns); + } + + if (statement->binds) { + _php3_hash_destroy(statement->binds); + efree(statement->binds); + } + + if (statement->defines) { + _php3_hash_destroy(statement->defines); + efree(statement->defines); + } + + efree(statement); +} + +/* }}} */ +/* {{{ _oci8_close_conn() */ + +static void +_oci8_close_conn(oci8_connection *connection) +{ + OCI8_TLS_VARS; + + if (! connection) { + return; + } + + /* + as the connection is "only" a in memory service context we do not disconnect from oracle. + */ + + oci8_debug("_oci8_close_conn: id=%d",connection->id); + + if (connection->descriptors) { + _php3_hash_destroy(connection->descriptors); + efree(connection->descriptors); + } + + if (connection->pServiceContext) { + OCIHandleFree((dvoid *) connection->pServiceContext, (ub4) OCI_HTYPE_SVCCTX); + } + + if (connection->pError) { + OCIHandleFree((dvoid *) connection->pError, (ub4) OCI_HTYPE_ERROR); + } + + efree(connection); +} + +/* }}} */ +/* {{{ oci8_error() */ + +static ub4 +oci8_error(OCIError *err_p, char *what, sword status) +{ + text errbuf[512]; + ub4 errcode = 0; + + switch (status) { + case OCI_SUCCESS: + break; + case OCI_SUCCESS_WITH_INFO: + php3_error(E_WARNING, "%s: OCI_SUCCESS_WITH_INFO", what); + break; + case OCI_NEED_DATA: + php3_error(E_WARNING, "%s: OCI_NEED_DATA", what); + break; + case OCI_NO_DATA: + php3_error(E_WARNING, "%s: OCI_NO_DATA", what); + break; + case OCI_ERROR: + OCIErrorGet(err_p, (ub4)1, NULL, &errcode, errbuf, + (ub4)sizeof(errbuf), (ub4)OCI_HTYPE_ERROR); + php3_error(E_WARNING, "%s: %s", what, errbuf); + break; + case OCI_INVALID_HANDLE: + php3_error(E_WARNING, "%s: OCI_INVALID_HANDLE", what); + break; + case OCI_STILL_EXECUTING: + php3_error(E_WARNING, "%s: OCI_STILL_EXECUTING", what); + break; + case OCI_CONTINUE: + php3_error(E_WARNING, "%s: OCI_CONTINUE", what); + break; + default: + break; + } + return errcode; +} + +/* }}} */ +/* {{{ NYI oci8_ping() */ + +#if 0 /* XXX NYI */ +/* test if a connection is still alive and return 1 if it is */ +static int oci8_ping(oci8_connection *conn) +{ + /* XXX FIXME not yet implemented */ + return 1; +} +#endif + +/* }}} */ + +/************************* INTERNAL FUNCTIONS *************************/ + +/* {{{ oci8_debugcol() */ +#if 0 +static void oci8_debugcol(oci8_out_column *column,const char *format,...) +{ + OCI8_TLS_VARS; + + if (OCI8_GLOBAL(php3_oci8_module).debug_mode) { + char buffer[1024]; + char colbuffer[1024]; + va_list args; + + va_start(args, format); + vsnprintf(buffer, sizeof(buffer)-1, format, args); + va_end(args); + buffer[sizeof(buffer)-1] = '\0'; + + sprintf(colbuffer,"name=%s,type=%d,size4=%ld,size2=%d,storage_size4=%ld,indicator=%d,retcode=%d,rlen=%ld", + column->name,column->type,column->size4,column->size2,column->storage_size4,column->indicator,column->retcode,column->rlen); + + if (php3_header()) { + php3_printf("OCIDebug:%s - %s
\n",buffer,colbuffer); + } + } +} +#endif +/* }}} */ +/* {{{ oci8_debug() */ + +static void oci8_debug(const char *format,...) +{ + OCI8_TLS_VARS; + + if (OCI8_GLOBAL(php3_oci8_module).debug_mode) { + char buffer[1024]; + va_list args; + + va_start(args, format); + vsnprintf(buffer, sizeof(buffer)-1, format, args); + va_end(args); + buffer[sizeof(buffer)-1] = '\0'; + if (php3_header()) { + php3_printf("OCIDebug: %s
\n", buffer); + } + } +} + +/* }}} */ +/* {{{ oci8_get_conn() */ + +static oci8_connection * +oci8_get_conn(int conn_ind, const char *func, HashTable *list, HashTable *plist) +{ + int type; + oci8_connection *connection; + OCI8_TLS_VARS; + + connection = (oci8_connection *)php3_list_find(conn_ind, &type); + if (!connection || !OCI8_CONN_TYPE(type)) { + php3_error(E_WARNING, "%s: invalid connection %d", func, conn_ind); + return (oci8_connection *)NULL; + } + return connection; +} + +/* }}} */ +/* {{{ oci8_get_stmt() */ + +static oci8_statement * +oci8_get_stmt(int stmt_ind, const char *func, HashTable *list) +{ + int type; + oci8_statement *statement; + OCI8_TLS_VARS; + + statement = (oci8_statement *)php3_list_find(stmt_ind, &type); + if (!statement || !OCI8_STMT_TYPE(type)) { + php3_error(E_WARNING, "%s: invalid statement %d", func, stmt_ind); + return (oci8_statement *)NULL; + } + return statement; +} + +/* }}} */ +/* {{{ oci8_get_col() */ + +static oci8_out_column * +oci8_get_col(oci8_statement *statement, int col, pval *pval, char *func) +{ + oci8_out_column *outcol = NULL; + int i; + OCI8_TLS_VARS; + + if (pval) { + if (pval->type == IS_STRING) { + for (i = 0; i < statement->ncolumns; i++) { + outcol = oci8_get_col(statement, i + 1, 0, func); + if (outcol == NULL) { + continue; + } else if (((int) outcol->name_len == pval->value.str.len) + && (! strncmp(outcol->name,pval->value.str.val,pval->value.str.len))) { + return outcol; + } + } + } else { + convert_to_long(pval); + + return oci8_get_col(statement,pval->value.lval,0,func); + } + } else if (col != -1) { + if (_php3_hash_index_find(statement->columns, col, (void **)&outcol) == FAILURE) { + php3_error(E_WARNING, "%s: invalid column %d", func, col); + return NULL; + } + return outcol; + } + + return NULL; +} + +/* }}} */ +/* {{{ oci8_make_pval() */ + +static int +oci8_make_pval(pval *value,int stmt_ind,oci8_out_column *column, char *func,HashTable *list, int mode) +{ + size_t size; + oci8_statement *statement; + oci8_descriptor *descr; + ub4 loblen; + char *buffer; + + /* + oci8_debug("oci8_make_pval: %16s,rlen = %4d,storage_size4 = %4d,size2 = %4d,indicator %4d, retcode = %4d", + column->name,column->rlen,column->storage_size4,column->size2,column->indicator,column->retcode); + */ + + memset(value,0,sizeof(pval)); + + statement = oci8_get_stmt(stmt_ind, "oci8_make_pval", list); + + if (column->indicator == -1) { /* column is NULL */ + var_reset(value); /* XXX we NEED to make sure that there's no data attached to this yet!!! */ + return 0; + } + + if (column->is_descr) { + if ((column->type != SQLT_RDD) && (mode & OCI_RETURN_LOBS)) { + /* OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */ + + if (_php3_hash_index_find(statement->conn->descriptors,(int) column->data, (void **)&descr) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor %d",column->data); + return -1; + } + + loblen = oci8_loaddesc(statement->conn,descr,&buffer); + + if (loblen > 0) { + value->type = IS_STRING; + value->value.str.len = loblen; + value->value.str.val = buffer; + } else { + var_reset(value); + } + } else { /* return the locator */ + object_init(value); + + add_property_long(value, "connection", statement->conn->id); + add_property_long(value, "descriptor", (long) column->data); + + if (column->type != SQLT_RDD) { /* ROWIDs don't have any user-callable methods */ + if ((column->type != SQLT_BFILEE) && (column->type != SQLT_CFILEE)) { + add_method(value, "save", php3_oci8_savedesc); /* oracle does not support writing of files as of now */ + } + add_method(value, "load", php3_oci8_loaddesc); + } + /* there is NO free call here, 'cause the memory gets deallocated together with the statement! */ + } + } else { + switch (column->retcode) { + case 1406: /* ORA-01406 XXX truncated value */ + /* this seems to be a BUG in oracle with 1-digit numbers */ + /* + oci8_debugcol(column,"truncated"); + */ + size = column->indicator - 1; /* when value is truncated indicator contains the lenght */ + break; + + case 0: /* intact value */ + /* + oci8_debugcol(column,"OK"); + */ + size = column->rlen; + break; + + default: /* XXX we SHOULD maybe have a different behaviour for unknown results! */ + var_reset(value); + return 0; + } + + value->type = IS_STRING; + value->value.str.len = size; + value->value.str.val = estrndup(column->data,size); + } + + return 0; +} + +/* }}} */ +/* {{{ oci8_parse() */ + +static int +oci8_parse(oci8_connection *connection, text *query, ub4 len, HashTable *list) +{ + oci8_statement *statement; + sword error; + OCI8_TLS_VARS; + + statement = ecalloc(1,sizeof(oci8_statement)); + OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&statement->pStmt, + OCI_HTYPE_STMT, + 0, + NULL); + OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&statement->pError, + OCI_HTYPE_ERROR, + 0, + NULL); + error = oci8_error(statement->pError, "OCIParse", + OCIStmtPrepare(statement->pStmt, connection->pError, + query, len, + OCI_NTV_SYNTAX, OCI_DEFAULT)); + if (error) { + return 0; + } + + statement->last_query = estrdup(query); + statement->conn = connection; + statement->id = php3_list_insert(statement, OCI8_GLOBAL(php3_oci8_module).le_stmt); + + oci8_debug("oci8_parse \"%s\" id=%d conn=%d", + query, + statement->id, + statement->conn->id); + + return statement->id; +} + +/* }}} */ +/* {{{ oci8_execute() */ + +static int +oci8_execute(oci8_statement *statement, char *func,ub4 mode) +{ + oci8_out_column *outcol; + oci8_out_column column; + OCIParam *param = 0; + text *colname; + ub4 counter; + sword error; + ub2 define_type; + ub2 stmttype; + ub4 iters; + ub4 colcount; + ub2 storage_size2; + OCI8_TLS_VARS; + + error = oci8_error( + statement->pError, + "OCIAttrGet OCI_HTYPE_STMT/OCI_ATTR_STMT_TYPE", + OCIAttrGet( + (dvoid *)statement->pStmt, + OCI_HTYPE_STMT, + (ub2 *)&stmttype, + (ub4 *)0, + OCI_ATTR_STMT_TYPE, + statement->pError)); + + if (error) { + return 0; + } + + if (stmttype == OCI_STMT_SELECT) { + iters = 0; + } else { + iters = 1; + } + + error = oci8_error( + statement->pError, + "OCIStmtExecute", + OCIStmtExecute( + statement->conn->pServiceContext, + statement->pStmt, + statement->pError, + iters, + 0, + NULL, + NULL, + mode)); + if (error) { + return 0; + } + + + if (stmttype == OCI_STMT_SELECT && (statement->executed == 0)) { + /* we only need to do the define step is this very statement is executed the first time! */ + statement->executed++; + + statement->columns = emalloc(sizeof(HashTable)); + if (!statement->columns || + _php3_hash_init(statement->columns, 13, NULL,(void (*)(void *))_oci8_free_column, 0) == FAILURE) { + /* out of memory */ + return 0; + } + +#if 0 + error = oci8_error( + statement->pError, + "OCIHandleAlloc OCI_DTYPE_PARAM", + OCIHandleAlloc( + OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)¶m, + OCI_DTYPE_PARAM, + 0, + NULL)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } +#endif + OCIHandleAlloc( + OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)¶m, + OCI_DTYPE_PARAM, + 0, + NULL); + + + counter = 1; + + error = oci8_error( + statement->pError, + "OCIAttrGet OCI_HTYPE_STMT/OCI_ATTR_PARAM_COUNT", + OCIAttrGet( + (dvoid *)statement->pStmt, + OCI_HTYPE_STMT, + (dvoid *)&colcount, + (ub4 *)0, + OCI_ATTR_PARAM_COUNT, + statement->pError)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } + + statement->ncolumns = colcount; + + for (counter = 1; counter <= colcount; counter++) { + memset(&column,0,sizeof(oci8_out_column)); + + if (_php3_hash_index_update(statement->columns, counter, &column, + sizeof(oci8_out_column), (void**) &outcol) == FAILURE) { + efree(statement->columns); + /* out of memory */ + return 0; + } + + outcol->statement = statement; + + error = oci8_error( + statement->pError, + "OCIParamGet OCI_HTYPE_STMT", + OCIParamGet( + (dvoid *)statement->pStmt, + OCI_HTYPE_STMT, + statement->pError, + (dvoid*)¶m, + counter)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } + + error = oci8_error( + statement->pError, + "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_DATA_TYPE", + OCIAttrGet( + (dvoid *)param, + OCI_DTYPE_PARAM, + (dvoid *)&outcol->type, + (ub4 *)0, + OCI_ATTR_DATA_TYPE, + statement->pError)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } + + error = oci8_error( + statement->pError, + "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_DATA_SIZE", + OCIAttrGet( + (dvoid *)param, + OCI_DTYPE_PARAM, + (dvoid *)&storage_size2, + (dvoid *)0, + OCI_ATTR_DATA_SIZE, + statement->pError)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } + + outcol->storage_size4 = storage_size2; + + error = oci8_error( + statement->pError, + "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_NAME", + OCIAttrGet( + (dvoid *)param, + OCI_DTYPE_PARAM, + (dvoid **)&colname, /* XXX this string is NOT zero terminated!!!! */ + (ub4 *)&outcol->name_len, + (ub4)OCI_ATTR_NAME, + statement->pError)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } + + outcol->name = estrndup(colname,outcol->name_len); + + /* Remember the size Oracle told us, we have to increase the + * storage size for some types. + */ + + outcol->size4 = outcol->storage_size4; + + /* find a user-setted define */ + if (statement->defines) { + _php3_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define); + } + + switch (outcol->type) { + case SQLT_RSET: /* ref. cursor XXX NYI */ + define_type = -1; + break; + + case SQLT_RDD: /* ROWID */ + case SQLT_BLOB: /* binary LOB */ + case SQLT_CLOB: /* character LOB */ + case SQLT_BFILE: /* binary file LOB */ + define_type = outcol->type; + outcol->is_descr = 1; + outcol->storage_size4 = -1; + break; + + case SQLT_LBI: + case SQLT_LNG: + case SQLT_BIN: + define_type = SQLT_STR; + /* XXX this should be user-settable!! */ + outcol->storage_size4 = OCI8_MAX_DATA_SIZE; /* 2MB */ + break; + + default: + define_type = SQLT_STR; + if ((outcol->type == SQLT_DAT) || (outcol->type == SQLT_NUM)) { + outcol->storage_size4 = 256; /* XXX this should fit "most" NLS date-formats and Numbers */ + } else { + outcol->storage_size4++; /* add one for string terminator */ + } + break; + } + + error = oci8_error( + statement->pError, + "OCIDefineByPos", + OCIDefineByPos( + statement->pStmt, /* IN/OUT handle to the requested SQL query */ + (OCIDefine **)&outcol->pDefine, /* IN/OUT pointer to a pointer to a define handle */ + statement->pError, /* IN/OUT An error handle */ + counter, /* IN position in the select list */ + (dvoid *)0, /* IN/OUT pointer to a buffer */ + outcol->storage_size4, /* IN The size of each valuep buffer in bytes */ + define_type, /* IN The data type */ + (dvoid *)&outcol->indicator, /* IN pointer to an indicator variable or arr */ + (ub2 *)&outcol->size2, /* IN/OUT Pointer to array of length of data fetched */ + (ub2 *)&outcol->retcode, /* OUT Pointer to array of column-level return codes */ + OCI_DYNAMIC_FETCH)); /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */ + if (error) { + return 0; /* XXX we loose memory!!! */ + } + + error = oci8_error( + statement->pError, + "OCIDefineDynamic", + OCIDefineDynamic( + outcol->pDefine, + statement->pError, + outcol, + oci8_define_callback)); + if (error) { + return 0; /* XXX we loose memory!!! */ + } + } + } + return 1; +} + +/* }}} */ +/* {{{ oci8_fetch() */ + +static int +oci8_fetch(oci8_statement *statement, ub4 nrows, char *func) +{ + sword error; + int i; + oci8_out_column *column; + pval *pval; + OCI8_TLS_VARS; + + error = OCIStmtFetch(statement->pStmt, statement->pError, nrows, + OCI_FETCH_NEXT, OCI_DEFAULT); + + if (error == OCI_NO_DATA) { + return 0; + } + + if (error == OCI_SUCCESS_WITH_INFO || error == OCI_SUCCESS) { + /* do the stuff needed for OCIDefineByName */ + for (i = 0; i < statement->ncolumns; i++) { + column = oci8_get_col(statement, i + 1, 0, "OCIFetch"); + if (column == NULL) { /* should not happen... */ + continue; + } + + if ((column->define) && (! column->is_descr)) { + pval = column->define->pval; + + if (! column->define->data) { /* oracle has NOT called our define_callback (column value is NULL) */ + pval->value.str.val = emalloc(column->storage_size4); + column->define->data = pval->value.str.val; + } + + if (column->indicator == -1) { /* NULL */ + pval->value.str.len = 0; + } else { + if (column->retcode == 1406) { /*XXX ORA-01406 truncated value */ + /* this seems to be a BUG in oracle with 1-digit numbers */ + /* + oci8_debugcol(column,"truncated"); + */ + pval->value.str.len = column->indicator - 1; /* when value is truncated indicator contains the lenght */ + } else { + pval->value.str.len = column->rlen; + } + } + + pval->value.str.val[ pval->value.str.len ] = 0; + } + } + + return 1; + } + + oci8_error(statement->pError, func, error); + + return 0; +} + +/* }}} */ +/* {{{ oci8_loaddesc() */ +static ub4 +oci8_loaddesc(oci8_connection *connection, oci8_descriptor *mydescr, char **buffer) +{ + sword ociresult; + ub4 loblen; + + OCI8_TLS_VARS; + + ociresult = OCILobGetLength(connection->pServiceContext, connection->pError, mydescr->ocidescr, &loblen); + + if (ociresult) { + oci8_error(connection->pError, "OCILobGetLength", ociresult); + return 0; + } + + *buffer = emalloc(loblen + 1); + + if (! buffer) { + return 0; + } + + if (mydescr->type == OCI_DTYPE_FILE) { + ociresult = OCILobFileOpen(connection->pServiceContext, + connection->pError, + mydescr->ocidescr, + OCI_FILE_READONLY); + if (ociresult) { + oci8_error(connection->pError, "OCILobFileOpen", ociresult); + efree(buffer); + return 0; + } + } + + ociresult = OCILobRead(connection->pServiceContext, + connection->pError, + mydescr->ocidescr, + &loblen, /* IN/OUT bytes toread/read */ + 1, /* offset (starts with 1) */ + (dvoid *) *buffer, + loblen, /* size of buffer */ + (dvoid *)0, + (OCICallbackLobRead) 0, /* callback... */ + (ub2) 0, /* The character set ID of the buffer data. */ + (ub1) SQLCS_IMPLICIT); /* The character set form of the buffer data. */ + + if (ociresult) { + oci8_error(connection->pError, "OCILobRead", ociresult); + efree(buffer); + return 0; + } + + if (mydescr->type == OCI_DTYPE_FILE) { + ociresult = OCILobFileClose(connection->pServiceContext, + connection->pError, + mydescr->ocidescr); + if (ociresult) { + oci8_error(connection->pError, "OCILobFileClose", ociresult); + efree(buffer); + return 0; + } + } + + (*buffer)[ loblen ] = 0; + + oci8_debug("OCIloaddesc: size=%d",loblen); + + return loblen; +} +/* }}} */ +/* {{{ oci8_define_callback() */ + +static sb4 +oci8_define_callback(dvoid *octxp, + OCIDefine *defnp, + ub4 iter, /* 0-based execute iteration value */ + dvoid **bufpp, /* pointer to data */ + ub4 **alenp, /* size after value/piece has been read */ + ub1 *piecep, /* which piece */ + dvoid **indpp, /* indicator value */ + ub2 **rcodep) +{ + oci8_out_column *outcol; + oci8_define *define; + pval *pval, *tmp; + oci8_descriptor *pdescr, descr; + + outcol = (oci8_out_column *)octxp; + define = outcol->define; + + + if (outcol->is_descr) { + if (define && (! outcol->pdescr)) { /* column has been user-defined */ + if (_php3_hash_find(define->pval->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor property"); + return OCI_ERROR; + } else if (_php3_hash_index_find(outcol->statement->conn->descriptors, tmp->value.lval, (void **)&pdescr) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor"); + return OCI_ERROR; + } + outcol->pdescr = pdescr; + } else if (! outcol->pdescr) { /* we got no define value and teh descriptor hasn't been allocated yet */ + if (outcol->type == SQLT_BFILE) { + descr.type = OCI_DTYPE_FILE; + } else if (outcol->type == SQLT_RDD ) { + descr.type = OCI_DTYPE_ROWID; + } else { + descr.type = OCI_DTYPE_LOB; + } + + OCIDescriptorAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,(dvoid *)&(descr.ocidescr), descr.type, (size_t) 0, (dvoid **) 0); + + _php3_hash_index_update(outcol->statement->conn->descriptors, + outcol->statement->conn->descriptors_count,&descr,sizeof(oci8_descriptor),(void **)&pdescr); + + outcol->data = (void *) outcol->statement->conn->descriptors_count++; + outcol->pdescr = pdescr; + + oci8_debug("OCIExecute: new descriptor for %d -> %x",outcol->data,descr.ocidescr); + } + + if (! outcol->pdescr) { + php3_error(E_WARNING, "unable to find my descriptor"); + return OCI_ERROR; + } + + outcol->rlen = -1; + *bufpp = outcol->pdescr->ocidescr; + } else { /* "normal variable" */ + if (define) { + pval = define->pval; + convert_to_string(pval); + + if (pval->value.str.val) { + if ((pval->value.str.val==undefined_variable_string) || (pval->value.str.val==empty_string)) { + /* value was empty -> allocate it... */ + pval->value.str.val = 0; + } else if (pval->value.str.val != define->data) { + /* value has changed - and is maybe too small -> reallocate it! */ + efree(pval->value.str.val); + pval->value.str.val = 0; + } + } + + if (pval->value.str.val == 0) { + pval->value.str.val = emalloc(outcol->storage_size4); + define->data = pval->value.str.val; + } + outcol->data = pval->value.str.val; + } else if (! outcol->data) { + outcol->data = (text *) emalloc(outcol->storage_size4); + } + + if (! outcol->data) { + php3_error(E_WARNING, "OCIFetch: cannot allocate %d bytes!",outcol->storage_size4); + return OCI_ERROR; + } + + outcol->rlen = outcol->storage_size4; + *bufpp = outcol->data; + } + + outcol->indicator = 0; + outcol->retcode = 0; + + *alenp = &outcol->rlen; + *indpp = &outcol->indicator; + *rcodep = &outcol->retcode; + *piecep = OCI_ONE_PIECE; + +/* + oci8_debug("oci8_define_callback: %s,*bufpp = %x,**alenp = %d,**indpp = %d, **rcodep= %d, *piecep = %d", + outcol->name,*bufpp,**alenp,**(ub2**)indpp,**rcodep,*piecep); +*/ + + return OCI_CONTINUE; +} + +/* }}} */ +/* {{{ oci8_bind_in_callback() */ + +static sb4 +oci8_bind_in_callback(dvoid *ictxp, /* context pointer */ + OCIBind *bindp, /* bind handle */ + ub4 iter, /* 0-based execute iteration value */ + ub4 index, /* index of current array for PL/SQL or + row index for SQL */ + dvoid **bufpp, /* pointer to data */ + ub4 *alenp, /* size after value/piece has been read */ + ub1 *piecep, /* which piece */ + dvoid **indpp) /* indicator value */ +{ + oci8_bind *phpbind; + pval *val; + + phpbind = (oci8_bind *)ictxp; + + if (!phpbind || !(val = phpbind->value)) { + php3_error(E_WARNING, "!phpbind || !phpbind->val"); + return OCI_ERROR; + } + + if (phpbind->descr == 0) { /* "normal string bind */ + convert_to_string(val); + + *bufpp = val->value.str.val; + *alenp = phpbind->maxsize; + *indpp = (dvoid *)&phpbind->indicator; + } else { /* descriptor bind */ + *bufpp = phpbind->descr; + *alenp = -1; /* seems to be allright */ + *indpp = (dvoid *)&phpbind->indicator; + } + + *piecep = OCI_ONE_PIECE; /* pass all data in one go */ + + return OCI_CONTINUE; +} + +/* }}} */ +/* {{{ oci8_bind_out_callback() */ + +static sb4 +oci8_bind_out_callback(dvoid *ctxp, /* context pointer */ + OCIBind *bindp, /* bind handle */ + ub4 iter, /* 0-based execute iteration value */ + ub4 index, /* index of current array for PL/SQL or + row index for SQL */ + dvoid **bufpp, /* pointer to data */ + ub4 **alenpp, /* size after value/piece has been read */ + ub1 *piecep, /* which piece */ + dvoid **indpp, /* indicator value */ + ub2 **rcodepp) /* return code */ +{ + oci8_bind *phpbind; + pval *val; + + phpbind = (oci8_bind *)ctxp; + if (!phpbind) { + oci8_debug("oci8_bind_out_callback: phpbind = NULL"); + return OCI_ERROR; + } + + val = phpbind->value; + if (val == NULL) { + oci8_debug("oci8_bind_out_callback: phpbind->value = NULL"); + return OCI_ERROR; + } + + /* XXX risky, if the variable has been freed, nasty things + * could happen here. + */ + + if (val->type == IS_OBJECT) { + + } else if (val->type == IS_STRING) { + STR_FREE(val->value.str.val); + + phpbind->value->value.str.len = phpbind->maxsize; + phpbind->value->value.str.val = emalloc(phpbind->maxsize); + + oci8_debug("oci8_bind_out_callback: maxlen=%d",phpbind->maxsize); + + *alenpp = (ub4*) &phpbind->value->value.str.len; /* XXX we assume that php-pval len has 4 bytes */ + *bufpp = phpbind->value->value.str.val; + *piecep = OCI_ONE_PIECE; + *rcodepp = &phpbind->retcode; + *indpp = &phpbind->indicator; + } + + return OCI_CONTINUE; +} + +/* }}} */ +/* {{{ oci8_login() + */ + +static oci8_session *oci8_login(oci8_server* server,char *username,char *password,int persistent,HashTable *list, HashTable *plist) +{ + sword error; + oci8_session *session = 0; + OCISvcCtx *svchp = 0; + list_entry *le; + list_entry new_le; + char *hashed_details = 0; + int hashed_details_length; + OCI8_TLS_VARS; + + /* + check if we already have this user authenticated + + we will reuse authenticated users within a request no matter if the user requested a persistent + connections or not! + + but only as pesistent requested connections will be kept between requests! + */ + + hashed_details_length = sizeof("oci8_user_")-1 + + strlen(SAFE_STRING(username))+ + strlen(SAFE_STRING(password))+ + strlen(SAFE_STRING(server->dbname)); + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"oci8_user_%s%s%s", + SAFE_STRING(username), + SAFE_STRING(password), + SAFE_STRING(server->dbname)); + + if (_php3_hash_find(plist, hashed_details, hashed_details_length+1, (void **) &le)==SUCCESS) { + session = (oci8_session *) le->ptr; + } else if (_php3_hash_find(list, hashed_details, hashed_details_length+1, (void **) &le)==SUCCESS) { + session = (oci8_session *) le->ptr; + } + + if (session) { + oci8_debug("oci8_login persistent sess=%d",session->id); + return session; + } + + if (persistent) { + session = calloc(1,sizeof(oci8_session)); + } else { + session = ecalloc(1,sizeof(oci8_session)); + } + + if (! session) { + goto CLEANUP; + } + + session->persistent = persistent; + session->server = server; + + /* allocate temporary Service Context */ + error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&svchp, + OCI_HTYPE_SVCCTX, + 0, + NULL); + if (error != OCI_SUCCESS) { + oci8_error(server->pError, "oci8_login: OCIHandleAlloc OCI_HTYPE_SVCCTX", error); + goto CLEANUP; + } + + /* allocate private error-handle */ + error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&session->pError, + OCI_HTYPE_ERROR, + 0, + NULL); + if (error != OCI_SUCCESS) { + oci8_error(server->pError, "oci8_login: OCIHandleAlloc OCI_HTYPE_ERROR", error); + goto CLEANUP; + } + + /* allocate private session-handle */ + error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&session->pSession, + OCI_HTYPE_SESSION, + 0, + NULL); + if (error != OCI_SUCCESS) { + oci8_error(server->pError, "oci8_login: OCIHandleAlloc OCI_HTYPE_SESSION", error); + goto CLEANUP; + } + + /* Set the server handle in service handle */ + error = OCIAttrSet(svchp, + OCI_HTYPE_SVCCTX, + server->pServer, + 0, + OCI_ATTR_SERVER, + session->pError); + if (error != OCI_SUCCESS) { + oci8_error(session->pError, "oci8_login: OCIAttrSet OCI_ATTR_SERVER", error); + goto CLEANUP; + } + + /* set the username in user handle */ + error = OCIAttrSet((dvoid *) session->pSession, + (ub4) OCI_HTYPE_SESSION, + (dvoid *) username, + (ub4) strlen(username), + (ub4) OCI_ATTR_USERNAME, + session->pError); + if (error != OCI_SUCCESS) { + oci8_error(session->pError, "OCIAttrSet OCI_ATTR_USERNAME", error); + goto CLEANUP; + } + + /* set the password in user handle */ + error = OCIAttrSet((dvoid *) session->pSession, + (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, + (ub4) strlen(password), + (ub4) OCI_ATTR_PASSWORD, + session->pError); + if (error != OCI_SUCCESS) { + oci8_error(session->pError, "OCIAttrSet OCI_ATTR_PASSWORD", error); + goto CLEANUP; + } + + error = OCISessionBegin(svchp, + session->pError, + session->pSession, + (ub4) OCI_CRED_RDBMS, + (ub4) OCI_DEFAULT); + if (error != OCI_SUCCESS) { + oci8_error(session->pError, "OCISessionBegin", error); + goto CLEANUP; + } + + /* Free Temporary Service Context */ + OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX); + + new_le.ptr = session; + + if (persistent) { + session->id = php3_list_insert(session, OCI8_GLOBAL(php3_oci8_module).le_psession); + _php3_hash_update(plist, + hashed_details, + hashed_details_length+1, + (void *) &new_le, + sizeof(list_entry), + NULL); + } else { + session->id = php3_list_insert(session, OCI8_GLOBAL(php3_oci8_module).le_session); + _php3_hash_update(list, + hashed_details, + hashed_details_length+1, + (void *) &new_le, + sizeof(list_entry), + NULL); + } + + oci8_debug("oci8_login new sess=%d",session->id); + + if (hashed_details) { + efree(hashed_details); + } + + return session; + + CLEANUP: + if (hashed_details) { + efree(hashed_details); + } + + if (session) { + _oci8_logoff(session); + } + + efree(session); + + return 0; +} + +/* }}} */ +/* {{{ _oci8_logoff() + */ + +static void +_oci8_logoff(oci8_session *session) +{ + if (! session) { + return; + } + + oci8_debug("_oci8_logoff: sess=%d",session->id); +} + +/* }}} */ +/* {{{ _oci8_free_descr() + */ + +static void +_oci8_free_descr(oci8_descriptor *descr) +{ + OCI8_TLS_VARS; + + oci8_debug("oci8_free_descr: %x",descr->ocidescr); + + OCIDescriptorFree(descr->ocidescr, descr->type); +} +/* }}} */ +/* {{{ oci8_attach() + */ +static oci8_server *oci8_attach(char *dbname,int persistent,HashTable *list, HashTable *plist) +{ + oci8_server *server = 0; + list_entry *le; + list_entry new_le; + sword error; + char *hashed_details = 0; + int hashed_details_length; + OCI8_TLS_VARS; + + /* + check if we already have this server open + + we will reuse servers within a request no matter if the usere requested persistent + connections or not! + + but only as pesistent requested connections will be kept between requests! + */ + + hashed_details_length = sizeof("oci8_server_")-1 + strlen(SAFE_STRING((char *)dbname)); + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"oci8_server_%s",SAFE_STRING((char *)dbname)); + + if (_php3_hash_find(plist, hashed_details, hashed_details_length+1, (void **) &le)==SUCCESS) { + server = (oci8_server *) le->ptr; + } else if (_php3_hash_find(list, hashed_details, hashed_details_length+1, (void **) &le)==SUCCESS) { + server = (oci8_server *) le->ptr; + } + + if (server) { + oci8_debug("oci8_attach persistent conn=%d (%s)",server->id,server->dbname); + return server; + } + + + if (persistent) { + server = calloc(1,sizeof(oci8_server)); + } else { + server = ecalloc(1,sizeof(oci8_server)); + } + + if (! server) { + goto CLEANUP; + } + + server->persistent = persistent; + + strcpy(server->dbname,dbname); + + OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&server->pError, + OCI_HTYPE_ERROR, + 0, + NULL); + + OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&server->pServer, + OCI_HTYPE_SERVER, + 0, + NULL); + + error = OCIServerAttach(server->pServer, + server->pError, + dbname, + strlen(dbname), + (ub4) OCI_DEFAULT); + + if (error) { + oci8_error(server->pError, "oci8_attach", error); + goto CLEANUP; + } + + new_le.ptr = server; + + if (persistent) { + server->id = php3_list_insert(server,OCI8_GLOBAL(php3_oci8_module).le_pserver); + _php3_hash_update(plist, + hashed_details, + hashed_details_length+1, + (void *) &new_le, + sizeof(list_entry), + NULL); + } else { + server->id = php3_list_insert(server,OCI8_GLOBAL(php3_oci8_module).le_server); + _php3_hash_update(list, + hashed_details, + hashed_details_length+1, + (void *) &new_le, + sizeof(list_entry), + NULL); + } + + oci8_debug("oci8_attach new conn=%d (%s)",server->id,server->dbname); + + if (hashed_details) { + efree(hashed_details); + } + + return server; + + CLEANUP: + if (hashed_details) { + efree(hashed_details); + } + + if (server) { + _oci8_detach(server); + } + + return 0; +} + +/* }}} */ +/* {{{ _oci8_detach() + */ + +static void +_oci8_detach(oci8_server *server) +{ + if (! server) { + return; + } + + oci8_debug("_oci8_detach: conn=%d",server->id); +} + +/* }}} */ +/* {{{ oci8_do_connect() + Connect to an Oracle database and log on. returns a new session. + */ +static void oci8_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent) +{ + text *username, *password, *dbname; + pval *userParam, *passParam, *dbParam; + oci8_server *server = 0; + oci8_session *session = 0; + oci8_connection *connection = 0; + sword error; + OCI8_TLS_VARS; + + if (getParameters(ht, 3, &userParam, &passParam, &dbParam) == SUCCESS) { + convert_to_string(userParam); + convert_to_string(passParam); + convert_to_string(dbParam); + + username = userParam->value.str.val; + password = passParam->value.str.val; + dbname = dbParam->value.str.val; + } else if (getParameters(ht, 2, &userParam, &passParam) == SUCCESS) { + convert_to_string(userParam); + convert_to_string(passParam); + + username = userParam->value.str.val; + password = passParam->value.str.val; + dbname = (text *)""; + } else { + WRONG_PARAM_COUNT; + } + + connection = (oci8_connection *) ecalloc(1,sizeof(oci8_connection)); + + if (! connection) { + goto CLEANUP; + } + + server = oci8_attach(dbname,persistent,list,plist); + + if (! server) { + goto CLEANUP; + } + + persistent = server->persistent; /* if our server-context is not persistent we can't */ + + session = oci8_login(server,username,password,persistent,list,plist); + + if (! session) { + goto CLEANUP; + } + + persistent = session->persistent; /* if our session-context is not persistent we can't */ + + /* set our session */ + connection->session = session; + + /* allocate our private error-handle */ + error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&connection->pError, + OCI_HTYPE_ERROR, + 0, + NULL); + if (error != OCI_SUCCESS) { + oci8_error(server->pError, "oci8_do_connect: OCIHandleAlloc OCI_HTYPE_ERROR", error); + goto CLEANUP; + } + + /* allocate our service-context */ + error = OCIHandleAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv, + (dvoid **)&connection->pServiceContext, + OCI_HTYPE_SVCCTX, + 0, + NULL); + if (error != OCI_SUCCESS) { + oci8_error(connection->pError, "oci8_do_connect: OCIHandleAlloc OCI_HTYPE_SVCCTX", error); + goto CLEANUP; + } + + /* Set the server handle in service handle */ + error = OCIAttrSet(connection->pServiceContext, + OCI_HTYPE_SVCCTX, + server->pServer, + 0, + OCI_ATTR_SERVER, + connection->pError); + if (error != OCI_SUCCESS) { + oci8_error(connection->pError, "oci8_do_connect: OCIAttrSet OCI_ATTR_SERVER", error); + goto CLEANUP; + } + + /* Set the Authentication handle in the service handle */ + error = OCIAttrSet(connection->pServiceContext, + OCI_HTYPE_SVCCTX, + session->pSession, + 0, + OCI_ATTR_SESSION, + connection->pError); + if (error != OCI_SUCCESS) { + oci8_error(connection->pError, "oci8_do_connect: OCIAttrSet OCI_ATTR_SESSION", error); + goto CLEANUP; + } + + connection->id = php3_list_insert(connection, OCI8_GLOBAL(php3_oci8_module).le_conn); + connection->descriptors = emalloc(sizeof(HashTable)); + if (!connection->descriptors || + _php3_hash_init(connection->descriptors, 13, NULL,(void (*)(void *))_oci8_free_descr, 0) == FAILURE) { + goto CLEANUP; + } + + oci8_debug("oci8_do_connect: id=%d",connection->id); + + RETURN_LONG(connection->id); + + CLEANUP: + RETURN_FALSE; +} + +/* }}} */ + +/************************* EXTENSION FUNCTIONS *************************/ + +/* {{{ proto int OCIDefineByName(int stmt, string name, mixed &var [,int type]) + Define a PHP variable to an Oracle column by name. + if you want to define a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE defining!!! + */ + +void php3_oci8_definebyname(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *name, *var, *type; + oci8_statement *statement; + oci8_define *define, *tmp_define; + ub2 ocitype; + + ocitype = SQLT_STR; /* zero terminated string */ + + if (getParameters(ht, 4, &stmt, &name, &var, &type) == SUCCESS) { + convert_to_long(type); + ocitype = (ub2) type->value.lval; + } else if (getParameters(ht, 3, &stmt, &name, &var) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIDefineByName", list); + if (statement == NULL) { + RETURN_FALSE; + } + + convert_to_string(name); + + define = ecalloc(1,sizeof(oci8_define)); + if (!define) { + /* out of memory */ + RETURN_FALSE; + } + if (statement->defines == NULL) { + statement->defines = emalloc(sizeof(HashTable)); + if (statement->defines == NULL || + _php3_hash_init(statement->defines, 13, NULL, (void (*)(void *))oci8_free_define, 0) == FAILURE) { + /* out of memory */ + RETURN_FALSE; + } + } + if (_php3_hash_add(statement->defines, + name->value.str.val, + name->value.str.len, + define, + sizeof(oci8_define), + (void **)&tmp_define) == SUCCESS) { + efree(define); + define = tmp_define; + } else { + RETURN_FALSE; + } + + define->name = estrndup(name->value.str.val,name->value.str.len); + define->name_len = name->value.str.len; + define->type = ocitype; + define->pval = var; + + RETURN_TRUE; +} + +/* }}} */ +/* {{{ proto int OCIBindByName(int stmt, string name, mixed &var, int maxlength [,int type]) + Bind a PHP variable to an Oracle placeholder by name. + if you want to bind a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE binding!!! + */ + +void php3_oci8_bindbyname(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *name, *var, *maxlen, *tmp,*type; + oci8_statement *statement; + oci8_bind *bind, *tmp_bind; + oci8_descriptor *descr; + sword error; + ub2 ocitype; + sb4 ocimaxlen; + dvoid *mydescr = 0; + + ocitype = SQLT_STR; /* zero terminated string */ + + if (getParameters(ht, 5, &stmt, &name, &var, &maxlen,&type) == SUCCESS) { + convert_to_long(type); + ocitype = (ub2) type->value.lval; + convert_to_long(maxlen); + ocimaxlen = maxlen->value.lval; + } else if (getParameters(ht, 4, &stmt, &name, &var, &maxlen) == SUCCESS) { + convert_to_long(maxlen); ocimaxlen = maxlen->value.lval; + } else { + WRONG_PARAM_COUNT; + } + + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIBindByName", list); + if (statement == NULL) { + RETURN_FALSE; + } + + switch (var->type) { + case IS_OBJECT : + if (_php3_hash_find(var->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor property"); + RETURN_FALSE; + } + + if (_php3_hash_index_find(statement->conn->descriptors, tmp->value.lval, (void **)&descr) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor"); + RETURN_FALSE; + } + + mydescr = (dvoid *) descr->ocidescr; + + if (! mydescr) { + RETURN_FALSE; + } + break; + + default: + convert_to_string(var); + if (ocimaxlen == -1) { + if (var->value.str.len == 0) { + php3_error(E_WARNING, "OCIBindByName bindlength is 0"); + } + ocimaxlen = var->value.str.len + 1; /* SQLT_STR needs a trailing 0 - maybe we need to resize the var buffers????? */ + } + break; + } + + convert_to_string(name); + + bind = ecalloc(1,sizeof(oci8_bind)); + if (!bind) { + /* out of memory */ + RETURN_FALSE; + } + if (statement->binds == NULL) { + statement->binds = emalloc(sizeof(HashTable)); + if (statement->binds == NULL || + _php3_hash_init(statement->binds, 13, NULL, NULL, 0) == FAILURE) { + /* out of memory */ + RETURN_FALSE; + } + } + if (_php3_hash_next_index_insert(statement->binds, bind, + sizeof(oci8_bind), + (void **)&tmp_bind) == SUCCESS) { + efree(bind); + bind = tmp_bind; + } + + bind->value = var; + bind->descr = mydescr; + bind->maxsize = ocimaxlen; + + error = OCIBindByName(statement->pStmt, /* statement handle */ + (OCIBind **)&bind->pBind, /* bind hdl (will alloc) */ + statement->pError, /* error handle */ + name->value.str.val, /* placeholder name */ + name->value.str.len, /* placeholder length */ + (dvoid *)0, /* in/out data */ + ocimaxlen, /* max size of input/output data */ + (ub2)ocitype, /* in/out data type */ + (dvoid *)&bind->indicator, /* indicator (ignored) */ + (ub2 *)0, /* size array (ignored) */ + (ub2 *)&bind->retcode, /* return code (ignored) */ + (ub4)0, /* maxarr_len (PL/SQL only?) */ + (ub4 *)0, /* actual array size (PL/SQL only?) */ + OCI_DATA_AT_EXEC /* mode */); + if (error != OCI_SUCCESS) { + oci8_error(statement->pError, "OCIBindByName", error); + RETURN_FALSE; + } + error = OCIBindDynamic(bind->pBind, + statement->pError, + (dvoid *)bind, + oci8_bind_in_callback, + (dvoid *)bind, + oci8_bind_out_callback); + if (error != OCI_SUCCESS) { + oci8_error(statement->pError, "OCIBindDynamic", error); + RETURN_FALSE; + } + + RETURN_TRUE; +} + +/* }}} */ +/* {{{ proto string ocifreedesc(object lob) + */ + +void php3_oci8_freedesc(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *id, *conn, *desc; + oci8_connection *connection; + + OCI8_TLS_VARS; + + if (getThis(&id) == SUCCESS) { + if (_php3_hash_find(id->value.ht, "connection", sizeof("connection"), (void **)&conn) == FAILURE) { + php3_error(E_WARNING, "unable to find my statement property"); + RETURN_FALSE; + } + + connection = oci8_get_conn(conn->value.lval, "OCIfreedesc", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + if (_php3_hash_find(id->value.ht, "descriptor", sizeof("descriptor"), (void **)&desc) == FAILURE) { + php3_error(E_WARNING, "unable to find my locator property"); + RETURN_FALSE; + } + + oci8_debug("OCOfreedesc: descr=%d",desc->value.lval); + + _php3_hash_index_del(connection->descriptors,desc->value.lval); + + RETURN_TRUE; + } + + RETURN_FALSE; +} +/* }}} */ +/* {{{ proto string ocisavedesc(object lob) + */ + +void php3_oci8_savedesc(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *id, *tmp, *conn, *arg; + OCILobLocator *mylob; + oci8_connection *connection; + oci8_descriptor *descr; + sword ociresult; + ub4 loblen; + + OCI8_TLS_VARS; + + if (getThis(&id) == SUCCESS) { + if (_php3_hash_find(id->value.ht, "connection", sizeof("connection"), (void **)&conn) == FAILURE) { + php3_error(E_WARNING, "unable to find my statement property"); + RETURN_FALSE; + } + + connection = oci8_get_conn(conn->value.lval, "OCIsavedesc", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + if (_php3_hash_find(id->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) { + php3_error(E_WARNING, "unable to find my locator property"); + RETURN_FALSE; + } + + if (_php3_hash_index_find(connection->descriptors, tmp->value.lval, (void **)&descr) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor %d",tmp->value.lval); + RETURN_FALSE; + } + + mylob = (OCILobLocator *) descr->ocidescr; + + if (! mylob) { + RETURN_FALSE; + } + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + loblen = arg->value.str.len; + + if (loblen < 1) { + php3_error(E_WARNING, "Cannot save a lob wich size is less than 1 byte"); + RETURN_FALSE; + } + + ociresult = OCILobWrite(connection->pServiceContext, + connection->pError, + mylob, + &loblen, + (ub4) 1, + (dvoid *) arg->value.str.val, + (ub4) loblen, + OCI_ONE_PIECE, + (dvoid *)0, + (OCICallbackLobWrite) 0, + (ub2) 0, + (ub1) SQLCS_IMPLICIT ); + + oci8_debug("OCIsavedesc: size=%d",loblen); + + if (ociresult) { + oci8_error(connection->pError, "OCILobWrite", ociresult); + RETURN_FALSE; + } + + RETURN_TRUE; + } + + RETURN_FALSE; +} + +/* }}} */ +/* {{{ proto string ociloaddesc(object lob) + */ + +void php3_oci8_loaddesc(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *id, *tmp, *conn; + oci8_connection *connection; + oci8_descriptor *descr; + char *buffer; + ub4 loblen; + + OCI8_TLS_VARS; + + if (getThis(&id) == SUCCESS) { + if (_php3_hash_find(id->value.ht, "connection", sizeof("connection"), (void **)&conn) == FAILURE) { + php3_error(E_WARNING, "unable to find my statement property"); + RETURN_FALSE; + } + + connection = oci8_get_conn(conn->value.lval, "OCIsavedesc", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + if (_php3_hash_find(id->value.ht, "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) { + php3_error(E_WARNING, "unable to find my locator property"); + RETURN_FALSE; + } + + if (_php3_hash_index_find(connection->descriptors, tmp->value.lval, (void **)&descr) == FAILURE) { + php3_error(E_WARNING, "unable to find my descriptor %d",tmp->value.lval); + RETURN_FALSE; + } + + loblen = oci8_loaddesc(connection,descr,&buffer); + + if (loblen > 0) { + RETURN_STRINGL(buffer,loblen,0); + } + } + + RETURN_FALSE; +} +/* }}} */ +/* {{{ proto string OCINewDescriptor(int connection [,int type ]) + initialize a new empty descriptor LOB/FILE (LOB is default) + */ + +void php3_oci8_newdescriptor(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *conn, *type; + sword ociresult; + oci8_connection *connection; + oci8_descriptor descr; + int mylob; + + OCI8_TLS_VARS; + + descr.type = OCI_DTYPE_LOB; + + if (getParameters(ht, 2, &conn, &type) == SUCCESS) { + descr.type = type->value.lval; + } else if (getParameters(ht, 1, &conn) == FAILURE) { + WRONG_PARAM_COUNT; + } + + switch (descr.type) { + case OCI_DTYPE_FILE: + case OCI_DTYPE_LOB: + case OCI_DTYPE_ROWID: + break; + + default: + php3_error(E_WARNING, "Unknown descriptor type %d.",descr.type); + RETURN_FALSE; + } + + convert_to_long(conn); + + connection = oci8_get_conn(conn->value.lval, "OCINewDescriptor", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + ociresult = OCIDescriptorAlloc(OCI8_GLOBAL(php3_oci8_module).pEnv,(dvoid*)&(descr.ocidescr), descr.type, (size_t) 0, (dvoid **) 0); + + if (ociresult) { + oci8_error(connection->pError,"OCIDescriptorAlloc %d",ociresult); + RETURN_FALSE; + } + + _php3_hash_index_update(connection->descriptors, connection->descriptors_count,&descr,sizeof(oci8_descriptor),NULL); + + mylob = connection->descriptors_count++; + + oci8_debug("OCINewDescriptor: new descriptor for %d -> %x",mylob,descr.ocidescr); + + object_init(return_value); + add_property_long(return_value, "descriptor", (long) mylob); + add_property_long(return_value, "connection", conn->value.lval); + add_method(return_value, "free", php3_oci8_freedesc); + + switch (descr.type) { + case OCI_DTYPE_LOB : + add_method(return_value, "save", php3_oci8_savedesc); + /* breaktruh */ + case OCI_DTYPE_FILE : + add_method(return_value, "load", php3_oci8_loaddesc); + break; + + } + + add_method(return_value, "free", php3_oci8_freedesc); +} + +/* }}} */ +/* {{{ proto string OCIRollback(int conn) + rollback the current context + */ + +void php3_oci8_rollback(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *conn; + oci8_connection *connection; + sword ociresult; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &conn) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(conn); + + connection = oci8_get_conn(conn->value.lval, "OCIRollback", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + ociresult = OCITransRollback(connection->pServiceContext,connection->pError, (ub4)0); + + if (ociresult) { + oci8_error(connection->pError, "OCIRollback", ociresult); + RETURN_FALSE; + } + + RETURN_TRUE; +} + +/* }}} */ +/* {{{ proto string OCICommit(int conn) + commit the current context + */ + +void php3_oci8_commit(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *conn; + oci8_connection *connection; + sword ociresult; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &conn) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(conn); + + connection = oci8_get_conn(conn->value.lval, "OCICommit", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + ociresult = OCITransCommit(connection->pServiceContext,connection->pError, (ub4)0); + + if (ociresult) { + oci8_error(connection->pError, "OCICommit", ociresult); + RETURN_FALSE; + } + + RETURN_TRUE; +} + +/* }}} */ +/* {{{ proto string OCIColumnName(int stmt, int col) + Tell the name of a column. + */ + +void php3_oci8_columnname(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *col; + oci8_statement *statement; + oci8_out_column *outcol; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &stmt, &col) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIColumnName", list); + if (statement == NULL) { + RETURN_FALSE; + } + outcol = oci8_get_col(statement, -1, col, "OCIColumnName"); + if (outcol == NULL) { + RETURN_FALSE; + } + + RETURN_STRINGL(outcol->name, outcol->name_len, 1); +} + +/* }}} */ +/* {{{ proto int OCIColumnSize(int stmt, int col) + Tell the maximum data size of a column. + */ + +void php3_oci8_columnsize(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *col; + oci8_statement *statement; + oci8_out_column *outcol; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &stmt, &col) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIColumnSize", list); + if (statement == NULL) { + RETURN_FALSE; + } + outcol = oci8_get_col(statement, -1, col, "OCIColumnSize"); + if (outcol == NULL) { + RETURN_FALSE; + } + RETURN_LONG(outcol->size4); +} + +/* }}} */ +/* {{{ proto mixed OCIColumnType(int stmt, int col) + Tell the data type of a column. + */ + +void php3_oci8_columntype(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *col; + oci8_statement *statement; + oci8_out_column *outcol; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &stmt, &col) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIColumnType", list); + if (statement == NULL) { + RETURN_FALSE; + } + outcol = oci8_get_col(statement, -1, col, "OCIColumnType"); + if (outcol == NULL) { + RETURN_FALSE; + } + switch (outcol->type) { + case SQLT_DAT: + RETVAL_STRING("DATE",1); + break; + case SQLT_NUM: + RETVAL_STRING("NUMBER",1); + break; + case SQLT_LNG: + RETVAL_STRING("LONG",1); + break; + case SQLT_BIN: + RETVAL_STRING("RAW",1); + break; + case SQLT_LBI: + RETVAL_STRING("LONG RAW",1); + break; + case SQLT_CHR: + RETVAL_STRING("VARCHAR",1); + break; + case SQLT_AFC: + RETVAL_STRING("CHAR",1); + break; + case SQLT_BLOB: + RETVAL_STRING("BLOB",1); + break; + case SQLT_CLOB: + RETVAL_STRING("CLOB",1); + break; + case SQLT_BFILE: + RETVAL_STRING("BFILE",1); + break; + case SQLT_RDD: + RETVAL_STRING("ROWID",1); + break; + default: + RETVAL_LONG(outcol->type); + } +} + +/* }}} */ +/* {{{ proto int OCIColumnIsNULL(int stmt, int col) + Tell whether a column is NULL. + */ + +void php3_oci8_columnisnull(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *col; + oci8_statement *statement; + oci8_out_column *outcol; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &stmt, &col) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIColumnIsNULL", list); + if (statement == NULL) { + RETURN_FALSE; + } + outcol = oci8_get_col(statement, -1, col, "OCIColumnIsNULL"); + if (outcol == NULL) { + RETURN_FALSE; + } + if (outcol->indicator == -1) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} + +/* }}} */ +/* {{{ Proto void OCIDebug(int onoff) + Toggle internal debugging output for the OCI extension. + */ + +/* Disables or enables the internal debug output. + * By default it is disabled. + */ +void php3_oci8_internaldebug(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *arg; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + OCI8_GLOBAL(php3_oci8_module).debug_mode = arg->value.lval; +} + + +/* }}} */ +/* {{{ proto int OCIExecute(int stmt [,int mode]) + Execute a parsed statement. + */ + +void php3_oci8_execute(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt,*mode; + oci8_statement *statement; + ub4 execmode; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &stmt, &mode) == SUCCESS) { + convert_to_long(mode); + execmode = mode->value.lval; + } else if (getParameters(ht, 1, &stmt) == SUCCESS) { + execmode = OCI_COMMIT_ON_SUCCESS; + } else { + WRONG_PARAM_COUNT; + } + + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIExecute", list); + if (statement == NULL) { + RETURN_FALSE; + } + + if (oci8_execute(statement, "OCIExecute",execmode)) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} + +/* }}} */ +/* {{{ proto int OCIFetch(int stmt) + Prepare a new row of data for reading. + */ + +void php3_oci8_fetch(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt; + oci8_statement *statement; + ub4 nrows = 1; /* only one row at a time is supported for now */ + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &stmt) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + + statement = oci8_get_stmt(stmt->value.lval, "OCIFetch", list); + if (statement == NULL) { + RETURN_FALSE; + } + if (oci8_fetch(statement, nrows, "OCIFetch")) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} + +/* }}} */ +/* {{{ proto int OCIFetchInto(int stmt, array &output [, int mode]) + Fetch a row of result data into an array. + */ + +void php3_oci8_fetchinto(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *array, element, *fmode; + oci8_statement *statement; + oci8_out_column *column; + ub4 nrows = 1; + int i; + int mode = OCI_NUM; + OCI8_TLS_VARS; + + if (getParameters(ht, 3, &stmt, &array, &fmode) == SUCCESS) { + convert_to_long(fmode); + mode = fmode->value.lval; + } else if (getParameters(ht, 2, &stmt, &array) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIFetchInto", list); + if (statement == NULL) { + RETURN_FALSE; + } + + if (!oci8_fetch(statement, nrows, "OCIFetchInto")) { + RETURN_FALSE; + } + + /* + if we don't want NULL columns back, we need to recreate the array + as it could have a different number of enties for each fetched row + */ + if (! (mode & OCI_RETURN_NULLS)) { + if (array->type == IS_ARRAY) { + /* XXX is that right?? */ + _php3_hash_destroy(array->value.ht); + efree(array->value.ht); + var_reset(array); + } + } + + if (array->type != IS_ARRAY) { + if (array_init(array) == FAILURE) { + php3_error(E_WARNING, "OCIFetchInto: unable to convert arg 2 to array"); + RETURN_FALSE; + } + } + + for (i = 0; i < statement->ncolumns; i++) { + column = oci8_get_col(statement, i + 1, 0, "OCIFetchInto"); + if (column == NULL) { /* should not happen... */ + continue; + } + + if ((column->indicator == -1) && ((mode & OCI_RETURN_NULLS) == 0)) { + continue; + } + + if ((mode & OCI_NUM) || (! (mode & OCI_ASSOC))) { /* OCI_NUM is default */ + oci8_make_pval(&element,stmt->value.lval,column, "OCIFetchInto",list,mode); + _php3_hash_index_update(array->value.ht, i, (void *)&element, sizeof(pval), NULL); + } + + if (mode & OCI_ASSOC) { + oci8_make_pval(&element,stmt->value.lval,column, "OCIFetchInto",list,mode); + _php3_hash_update(array->value.ht, column->name, column->name_len+1, (void *)&element, sizeof(pval), NULL); + } + } + + RETURN_LONG(statement->ncolumns); +} + +/* }}} */ +/* {{{ proto int OCIFetchStatement(int stmt, array &output) + Fetch all rows of result data into an array. + */ + +void php3_oci8_fetchstatement(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *array, element, *fmode; + oci8_statement *statement; + oci8_out_column **columns; + pval **outarrs; + pval tmp; + ub4 nrows = 1; + int i; + int mode = OCI_NUM; + int rows = 0; + char namebuf[ 128 ]; + OCI8_TLS_VARS; + + if (getParameters(ht, 3, &stmt, &array, &fmode) == SUCCESS) { + convert_to_long(fmode); + mode = fmode->value.lval; + } else if (getParameters(ht, 2, &stmt, &array) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIFetchStatement", list); + if (statement == NULL) { + RETURN_FALSE; + } + + if (array->type != IS_ARRAY) { + if (array_init(array) == FAILURE) { + php3_error(E_WARNING, "OCIFetchStatement: unable to convert arg 2 to array"); + RETURN_FALSE; + } + } + + columns = emalloc(statement->ncolumns * sizeof(oci8_out_column *)); + outarrs = emalloc(statement->ncolumns * sizeof(pval)); + + for (i = 0; i < statement->ncolumns; i++) { + columns[ i ] = oci8_get_col(statement, i + 1, 0, "OCIFetchStatement"); + + array_init(&tmp); + + memcpy(namebuf,columns[ i ]->name, columns[ i ]->name_len); + namebuf[ columns[ i ]->name_len ] = 0; + + _php3_hash_update(array->value.ht, namebuf, columns[ i ]->name_len+1, (void *) &tmp, sizeof(pval), (void **) &(outarrs[ i ])); + } + + while (oci8_fetch(statement, nrows, "OCIFetchStatement")) { + for (i = 0; i < statement->ncolumns; i++) { + oci8_make_pval(&element,stmt->value.lval,columns[ i ], "OCIFetchStatement",list,OCI_RETURN_LOBS); + _php3_hash_index_update(outarrs[ i ]->value.ht, rows, (void *)&element, sizeof(pval), NULL); + } + rows++; + } + + efree(columns); + efree(outarrs); + + RETURN_LONG(rows); +} + +/* }}} */ +/* {{{ proto int OCIFreeStatement(int stmt) + Free all resources associated with a statement. + */ + +void php3_oci8_freestatement(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt; + oci8_statement *statement; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &stmt) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIFreeStatement", list); + if (statement == NULL) { + RETURN_FALSE; + } + + php3_list_delete(stmt->value.lval); + + RETURN_TRUE; +} + +/* }}} */ +/* {{{ proto int OCILogoff(int conn) + Disconnect from database. + */ + +/* Logs off and disconnects. + */ +void php3_oci8_logoff(INTERNAL_FUNCTION_PARAMETERS) +{ + oci8_connection *connection; + pval *arg; + int index, index_t; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + index = arg->value.lval; + connection = (oci8_connection *)php3_list_find(index, &index_t); + + if (!connection) { + oci8_debug("OCILogoff: connection == NULL."); + RETURN_FALSE; + } + + if (! OCI8_CONN_TYPE(index_t)) { + oci8_debug("OCILogoff: connection not found..."); + RETURN_FALSE; + } + + if (php3_list_delete(index) == SUCCESS) { + RETURN_TRUE; + } else { + oci8_debug("OCILogoff: php3_list_delete failed."); + RETURN_FALSE; + } +} + +/* }}} */ +/* {{{ proto int OCILogon(string user, string pass[, string db]) + Connect to an Oracle database and log on. returns a new session. + */ + +/* Connects to an Oracle 8 database and logs on. If the + * optional third parameter is not specified, PHP uses the environment + * variable ORACLE_SID to determine which database to connect to. + */ +void php3_oci8_logon(INTERNAL_FUNCTION_PARAMETERS) +{ + oci8_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); +} + +/* }}} */ +/* {{{ proto int OCIPLogon(string user, string pass[, string db]) + Connect to an Oracle database and log on. returns a new session. + */ + +/* Connects to an Oracle 8 database and logs on. If the + * optional third parameter is not specified, PHP uses the environment + * variable ORACLE_SID to determine which database to connect to. + */ +void php3_oci8_plogon(INTERNAL_FUNCTION_PARAMETERS) +{ + oci8_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1); +} + +/* }}} */ +/* {{{ proto int OCIError(int stmt|conn) + Return the last error of stmt|conn. If no error happened returns false. + */ + +void php3_oci8_error(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *mixed; + oci8_statement *statement; + oci8_connection *connection; + text errbuf[512]; + ub4 errcode = 0; + int type; + dvoid *errh = NULL; + + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &mixed) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(mixed); + + statement = (oci8_statement *)php3_list_find(mixed->value.lval, &type); + if (statement && OCI8_STMT_TYPE(type)) { + errh = statement->pError; + } else { + connection = (oci8_connection *)php3_list_find(mixed->value.lval, &type); + if (connection && OCI8_CONN_TYPE(type)) { + errh = connection->pError; + } + } + + if (! errh) { + php3_error(E_WARNING, "OCIError: unable to find Error handle"); + RETURN_FALSE; + } + + OCIErrorGet(errh,1,NULL,&errcode,errbuf,(ub4)sizeof(errbuf),(ub4)OCI_HTYPE_ERROR); + + if (errcode) { + array_init(return_value); + add_assoc_long(return_value, "code", errcode); + add_assoc_string(return_value, "message", errbuf, 1); + } else { + RETURN_FALSE; + } +} + +/* }}} */ +/* {{{ proto int OCINumCols(int stmt) + Return the number of result columns in a statement. + */ + +void php3_oci8_numcols(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt; + oci8_statement *statement; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &stmt) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCINumCols", list); + if (statement == NULL) { + RETURN_FALSE; + } + RETURN_LONG(statement->ncolumns); +} + +/* }}} */ +/* {{{ proto int OCIParse(int conn, string query) + Parse a query and return a statement. + */ + +void php3_oci8_parse(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *conn, *query; + oci8_connection *connection; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &conn, &query) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(conn); + convert_to_string(query); + + connection = oci8_get_conn(conn->value.lval, "OCIParse", list, plist); + if (connection == NULL) { + RETURN_FALSE; + } + + RETURN_LONG(oci8_parse(connection, + query->value.str.val, + query->value.str.len, + list)); +} + +/* }}} */ +/* {{{ proto string OCIResult(int stmt, mixed column) + Return a single column of result data. + */ + +void php3_oci8_result(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt, *col; + oci8_statement *statement; + oci8_out_column *outcol = NULL; + OCI8_TLS_VARS; + + if (getParameters(ht, 2, &stmt, &col) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(stmt); + + statement = oci8_get_stmt(stmt->value.lval, "OCIResult", list); + + if (statement == NULL) { + RETURN_FALSE; + } + + outcol = oci8_get_col(statement, -1, col, "OCIResult"); + + if (outcol == NULL) { + RETURN_FALSE; + } + + oci8_make_pval(return_value,stmt->value.lval,outcol, "OCIResult",list,0); +} + +/* }}} */ +/* {{{ proto string OCIServerVersion(int conn) + Return a string containing server version information. + */ + +void php3_oci8_serverversion(INTERNAL_FUNCTION_PARAMETERS) +{ + oci8_connection *connection; + pval *arg; + int index, index_t; + sword error; + char version[256]; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + index = arg->value.lval; + connection = (oci8_connection *)php3_list_find(index, &index_t); + if (!connection || !OCI8_CONN_TYPE(index_t)) { + RETURN_FALSE; + } + error = OCIServerVersion(connection->pServiceContext, + connection->pError, version, sizeof(version), + OCI_HTYPE_SVCCTX); + if (error != OCI_SUCCESS) { + oci8_error(connection->pError, "OCIServerVersion", error); + RETURN_FALSE; + } + RETURN_STRING(version,1); +} + +/* }}} */ +/* {{{ proto int OCIStatementType(int stmt) + Return the query type of an OCI statement. + */ + +/* XXX it would be better with a general interface to OCIAttrGet() */ + +void php3_oci8_statementtype(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt; + oci8_statement *statement; + ub2 stmttype; + sword error; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &stmt) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIStatementType", list); + if (statement == NULL) { + RETURN_FALSE; + } + + error = OCIAttrGet((dvoid *)statement->pStmt, OCI_HTYPE_STMT, + (ub2 *)&stmttype, (ub4 *)0, OCI_ATTR_STMT_TYPE, + statement->pError); + if (error != OCI_SUCCESS) { + oci8_error(statement->pError, "OCIStatementType", error); + RETURN_FALSE; + } + + switch (stmttype) { + case OCI_STMT_SELECT: + RETVAL_STRING("SELECT",1); + break; + case OCI_STMT_UPDATE: + RETVAL_STRING("UPDATE",1); + break; + case OCI_STMT_DELETE: + RETVAL_STRING("DELETE",1); + break; + case OCI_STMT_INSERT: + RETVAL_STRING("INSERT",1); + break; + case OCI_STMT_CREATE: + RETVAL_STRING("CREATE",1); + break; + case OCI_STMT_DROP: + RETVAL_STRING("DROP",1); + break; + case OCI_STMT_ALTER: + RETVAL_STRING("ALTER",1); + break; + case OCI_STMT_BEGIN: + RETVAL_STRING("BEGIN",1); + break; + case OCI_STMT_DECLARE: + RETVAL_STRING("DECLARE",1); + break; + default: + RETVAL_STRING("UNKNOWN",1); + } +} + +void php3_oci8_rowcount(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *stmt; + oci8_statement *statement; + ub4 rowcount; + sword error; + OCI8_TLS_VARS; + + if (getParameters(ht, 1, &stmt) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(stmt); + statement = oci8_get_stmt(stmt->value.lval, "OCIStatementType", list); + if (statement == NULL) { + RETURN_FALSE; + } + + error = OCIAttrGet((dvoid *)statement->pStmt, OCI_HTYPE_STMT, + (ub2 *)&rowcount, (ub4 *)0, OCI_ATTR_ROW_COUNT, + statement->pError); + + if (error != OCI_SUCCESS) { + oci8_error(statement->pError, "OCIRowCount", error); + RETURN_FALSE; + } + + RETURN_LONG(rowcount); +} + +/* }}} */ + +#endif /* HAVE_OCI8 */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/ext/oracle/oracle.c b/ext/oracle/oracle.c new file mode 100644 index 00000000000..780750fbf7f --- /dev/null +++ b/ext/oracle/oracle.c @@ -0,0 +1,1715 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997,1998 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Stig Sæther Bakken | + | Mitch Golden | + | Rasmus Lerdorf | + | Andreas Karajannis | + +----------------------------------------------------------------------+ + */ +#if defined(COMPILE_DL) +# if PHP_31 +# include "../phpdl.h" +# else +# ifdef THREAD_SAFE +# undef THREAD_SAFE +# endif +# include "dl/phpdl.h" +# endif +#endif +#include "php.h" +#include "oracle.h" + +#if HAVE_ORACLE +#if !(WIN32|WINNT) +#include "build-defs.h" +#endif +#include "snprintf.h" +#include "zend_globals.h" + +#ifndef min +#define min(a, b) ((a) > (b) ? (b) : (a)) +#endif + +#ifdef THREAD_SAFE + +void *oracle_mutex; +DWORD ORACLETls; +static int numthreads=0; + +typedef struct oracle_global_struct { + oracle_module php3_oracle_module; +} oracle_global_struct; + +#define ORACLE_GLOBAL(a) oracle_globals->a + +#define ORACLE_TLS_VARS \ + oracle_global_struct *oracle_globals = TlsGetValue(ORACLETls); + +#else +oracle_module php3_oracle_module; +#define ORACLE_GLOBAL(a) a +#define ORACLE_TLS_VARS +#endif + +#undef ORACLE_DEBUG + +#define DB_SIZE 65536 + +static oraConnection *ora_get_conn(HashTable *, int); +static int ora_add_cursor(HashTable *, oraCursor *); +static oraCursor *ora_get_cursor(HashTable *, int); +static void ora_del_cursor(HashTable *, int); +static char *ora_error(Cda_Def *); +static int ora_describe_define(oraCursor *); +static int _cursors_cleanup(list_entry *le); +static void _close_oraconn(oraConnection *conn); +static void _close_orapconn(oraConnection *conn); +static void _close_oracur(oraCursor *cur); +static int _ora_ping(oraConnection *conn); +int ora_set_param_values(oraCursor *cursor, int isout); + +void php3_Ora_Do_Logon(INTERNAL_FUNCTION_PARAMETERS, int persistent); + +function_entry oracle_functions[] = { + {"ora_bind", php3_Ora_Bind, NULL}, + {"ora_close", php3_Ora_Close, NULL}, + {"ora_commit", php3_Ora_Commit, NULL}, + {"ora_commitoff", php3_Ora_CommitOff, NULL}, + {"ora_commiton", php3_Ora_CommitOn, NULL}, + {"ora_do", php3_Ora_Do, NULL}, + {"ora_error", php3_Ora_Error, NULL}, + {"ora_errorcode", php3_Ora_ErrorCode, NULL}, + {"ora_exec", php3_Ora_Exec, NULL}, + {"ora_fetch", php3_Ora_Fetch, NULL}, + {"ora_fetch_into", php3_Ora_FetchInto, NULL}, + {"ora_columntype", php3_Ora_ColumnType, NULL}, + {"ora_columnname", php3_Ora_ColumnName, NULL}, + {"ora_columnsize", php3_Ora_ColumnSize, NULL}, + {"ora_getcolumn", php3_Ora_GetColumn, NULL}, + {"ora_numcols", php3_Ora_NumCols, NULL}, + {"ora_numrows", php3_Ora_NumRows, NULL}, + {"ora_logoff", php3_Ora_Logoff, NULL}, + {"ora_logon", php3_Ora_Logon, NULL}, + {"ora_plogon", php3_Ora_PLogon, NULL}, + {"ora_open", php3_Ora_Open, NULL}, + {"ora_parse", php3_Ora_Parse, NULL}, + {"ora_rollback", php3_Ora_Rollback, NULL}, + {NULL, NULL, NULL} +}; + +php3_module_entry oracle_module_entry = { + "Oracle", + oracle_functions, + php3_minit_oracle, + php3_mshutdown_oracle, + php3_rinit_oracle, + NULL, + php3_info_oracle, + STANDARD_MODULE_PROPERTIES +}; + +static const text *ora_func_tab[] = +{(text *) "unused", +/* 1, 2 */ (text *) "unused", (text *) "OSQL", +/* 3, 4 */ (text *) "unused", (text *) "OEXEC/OEXN", +/* 5, 6 */ (text *) "unused", (text *) "OBIND", +/* 7, 8 */ (text *) "unused", (text *) "ODEFIN", +/* 9, 10 */ (text *) "unused", (text *) "ODSRBN", +/* 11, 12 */ (text *) "unused", (text *) "OFETCH/OFEN", +/* 13, 14 */ (text *) "unused", (text *) "OOPEN", +/* 15, 16 */ (text *) "unused", (text *) "OCLOSE", +/* 17, 18 */ (text *) "unused", (text *) "unused", +/* 19, 20 */ (text *) "unused", (text *) "unused", +/* 21, 22 */ (text *) "unused", (text *) "ODSC", +/* 23, 24 */ (text *) "unused", (text *) "ONAME", +/* 25, 26 */ (text *) "unused", (text *) "OSQL3", +/* 27, 28 */ (text *) "unused", (text *) "OBNDRV", +/* 29, 30 */ (text *) "unused", (text *) "OBNDRN", +/* 31, 32 */ (text *) "unused", (text *) "unused", +/* 33, 34 */ (text *) "unused", (text *) "OOPT", +/* 35, 36 */ (text *) "unused", (text *) "unused", +/* 37, 38 */ (text *) "unused", (text *) "unused", +/* 39, 40 */ (text *) "unused", (text *) "unused", +/* 41, 42 */ (text *) "unused", (text *) "unused", +/* 43, 44 */ (text *) "unused", (text *) "unused", +/* 45, 46 */ (text *) "unused", (text *) "unused", +/* 47, 48 */ (text *) "unused", (text *) "unused", +/* 49, 50 */ (text *) "unused", (text *) "unused", +/* 51, 52 */ (text *) "unused", (text *) "OCAN", +/* 53, 54 */ (text *) "unused", (text *) "OPARSE", +/* 55, 56 */ (text *) "unused", (text *) "OEXFET", +/* 57, 58 */ (text *) "unused", (text *) "OFLNG", +/* 59, 60 */ (text *) "unused", (text *) "ODESCR", +/* 61, 62 */ (text *) "unused", (text *) "OBNDRA" +}; + +#if COMPILE_DL +DLEXPORT php3_module_entry *get_module() { return &oracle_module_entry; }; +#endif + +static int _cursors_cleanup(list_entry *le) +{ + ORACLE_TLS_VARS; + + if (le->type == ORACLE_GLOBAL(php3_oracle_module).le_cursor){ + oraCursor *curs = ((oraCursor *) le->ptr); + oraConnection *conn = curs->conn_ptr; + + if ((!(conn->open)) && (curs->open > 0)){ + oclose(&curs->cda); + curs->open = 0; + } + } + return 0; +} + +static void _close_oraconn(oraConnection *conn) +{ + ORACLE_TLS_VARS; + + conn->open = 0; + _php3_hash_apply(ORACLE_GLOBAL(php3_oracle_module).resource_list, + (int (*)(void *))_cursors_cleanup); + + ologof(&conn->lda); + ORACLE_GLOBAL(php3_oracle_module).num_links--; + efree(conn); +} + +static void _close_orapconn(oraConnection *conn) +{ + ORACLE_TLS_VARS; + + conn->open = 0; + _php3_hash_apply(ORACLE_GLOBAL(php3_oracle_module).resource_plist, + (int (*)(void *))_cursors_cleanup); + + ologof(&conn->lda); + free(conn); + ORACLE_GLOBAL(php3_oracle_module).num_links--; + ORACLE_GLOBAL(php3_oracle_module).num_persistent--; +} + +static void _close_oracur(oraCursor *cur) +{ + int i; + + if (cur){ + if (cur->query){ + efree(cur->query); + } + if (cur->params){ + _php3_hash_destroy(cur->params); + efree(cur->params); + cur->params = NULL; + } + if (cur->columns){ + for(i = 0; i < cur->ncols; i++){ + if (cur->columns[i].buf) + efree(cur->columns[i].buf); + } + efree(cur->columns); + cur->columns = NULL; + } + if (cur->open){ + oclose(&cur->cda); + cur->open = 0; + } + efree(cur); + } +} + +int php3_minit_oracle(INIT_FUNC_ARGS) +{ +#if defined(THREAD_SAFE) + oracle_global_struct *oracle_globals; + PHP3_MUTEX_ALLOC(oracle_mutex); + PHP3_MUTEX_LOCK(oracle_mutex); + numthreads++; + if (numthreads==1){ + if (!PHP3_TLS_PROC_STARTUP(ORACLETls)){ + PHP3_MUTEX_UNLOCK(oracle_mutex); + PHP3_MUTEX_FREE(oracle_mutex); + return FAILURE; + } + } + PHP3_MUTEX_UNLOCK(oracle_mutex); + if(!PHP3_TLS_THREAD_INIT(ORACLETls,oracle_globals,oracle_global_struct)){ + PHP3_MUTEX_FREE(oracle_mutex); + return FAILURE; + } +#endif + + ORACLE_GLOBAL(php3_oracle_module).le_conn = + register_list_destructors(_close_oraconn,NULL); + ORACLE_GLOBAL(php3_oracle_module).le_cursor = + register_list_destructors(_close_oracur,NULL); + + if (cfg_get_long("oracle.allow_persistent", + &ORACLE_GLOBAL(php3_oracle_module).allow_persistent) + == FAILURE) { + ORACLE_GLOBAL(php3_oracle_module).allow_persistent = -1; + } + if (cfg_get_long("oracle.max_persistent", + &ORACLE_GLOBAL(php3_oracle_module).max_persistent) + == FAILURE) { + ORACLE_GLOBAL(php3_oracle_module).max_persistent = -1; + } + if (cfg_get_long("oracle.max_links", + &ORACLE_GLOBAL(php3_oracle_module).max_links) + == FAILURE) { + ORACLE_GLOBAL(php3_oracle_module).max_links = -1; + } + + ORACLE_GLOBAL(php3_oracle_module).num_persistent = 0; + + ORACLE_GLOBAL(php3_oracle_module).le_cursor = + register_list_destructors(_close_oracur, NULL); + ORACLE_GLOBAL(php3_oracle_module).le_conn = + register_list_destructors(_close_oraconn, NULL); + ORACLE_GLOBAL(php3_oracle_module).le_pconn = + register_list_destructors(NULL, _close_orapconn); + + REGISTER_LONG_CONSTANT("ORA_BIND_INOUT", 0, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ORA_BIND_IN", 1, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ORA_BIND_OUT", 2, CONST_CS | CONST_PERSISTENT); + + return SUCCESS; +} + +int php3_rinit_oracle(INIT_FUNC_ARGS) +{ + ORACLE_TLS_VARS; + + ORACLE_GLOBAL(php3_oracle_module).num_links = + ORACLE_GLOBAL(php3_oracle_module).num_persistent; + /* + ORACLE_GLOBAL(php3_oracle_module).defaultlrl = 0; + ORACLE_GLOBAL(php3_oracle_module).defaultbinmode = 0; + ORACLE_GLOBAL(php3_oracle_module).defaultconn = 0; + */ + return SUCCESS; +} + + +int php3_mshutdown_oracle(SHUTDOWN_FUNC_ARGS) +{ + ORACLE_TLS_VARS; +#ifdef THREAD_SAFE + PHP3_TLS_THREAD_FREE(oracle_globals); + PHP3_MUTEX_LOCK(oracle_mutex); + numthreads--; + if (numthreads<1) { + PHP3_TLS_PROC_SHUTDOWN(ORACLETls); + PHP3_MUTEX_UNLOCK(oracle_mutex); + PHP3_MUTEX_FREE(oracle_mutex); + return SUCCESS; + } + PHP3_MUTEX_UNLOCK(oracle_mutex); +#endif + return SUCCESS; + +} + +static int _ora_ping(oraConnection *conn) +{ + Cda_Def cda; + + if (oopen(&cda, &conn->lda, (text *) 0, -1, -1, (text *) 0, -1)) { + return 0; + } + + if (oparse(&cda, "select sysdate from dual", (sb4) - 1, 0, VERSION_7)) { + oclose(&cda); + return 0; + } + + oclose(&cda); + return 1; + +} + +/* + ** PHP functions +*/ + +/* {{{ proto int ora_logon(string user, string password) + Open an Oracle connection */ +void php3_Ora_Logon(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_Ora_Do_Logon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto int ora_plogon(string user, string password) + Open a persistant Oracle connection */ +void php3_Ora_PLogon(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_Ora_Do_Logon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +void php3_Ora_Do_Logon(INTERNAL_FUNCTION_PARAMETERS, int persistent) +{ + char *user = NULL; + char *pwd = NULL; + pval *arg1, *arg2; + oraConnection *db_conn; + list_entry *index_ptr; + char *hashed_details; + int hashed_len, len, id; + ORACLE_TLS_VARS; + + ORACLE_GLOBAL(php3_oracle_module).resource_list = list; + ORACLE_GLOBAL(php3_oracle_module).resource_plist = plist; + + if (getParameters(ht, 2, &arg1, &arg2) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_string(arg1); + convert_to_string(arg2); + + user = arg1->value.str.val; + pwd = arg2->value.str.val; + + if (!ORACLE_GLOBAL(php3_oracle_module).allow_persistent) { + persistent = 0; + } + + if (ORACLE_GLOBAL(php3_oracle_module).max_links != -1 && + ORACLE_GLOBAL(php3_oracle_module).num_links >= + ORACLE_GLOBAL(php3_oracle_module).max_links) { + php3_error(E_WARNING, "Oracle: Too many open links (%d)", + ORACLE_GLOBAL(php3_oracle_module).num_links); + RETURN_FALSE; + } + + /* the user requested a persistent connection */ + if (persistent && + ORACLE_GLOBAL(php3_oracle_module).max_persistent != -1 && + ORACLE_GLOBAL(php3_oracle_module).num_persistent >= + ORACLE_GLOBAL(php3_oracle_module).max_persistent) { + php3_error(E_WARNING,"Oracle: Too many open persistent links (%d)", + ORACLE_GLOBAL(php3_oracle_module).num_persistent); + RETURN_FALSE; + } + + len = strlen(user) + strlen(pwd) + 9; + hashed_details = emalloc(len); + + if (hashed_details == NULL) { + php3_error(E_WARNING, "Out of memory"); + RETURN_FALSE; + } + + hashed_len = _php3_sprintf(hashed_details, "ora_%s_%s", user, pwd); + + /* try to find if we already have this link in our persistent list, + * no matter if it is to be persistent or not + */ + + if (_php3_hash_find(plist, hashed_details, hashed_len + 1, + (void **) &index_ptr) == FAILURE) { + /* the link is not in the persistent list */ + list_entry new_index_ptr; + + if (persistent) + db_conn = (oraConnection *)malloc(sizeof(oraConnection)); + else + db_conn = (oraConnection *)emalloc(sizeof(oraConnection)); + + if (db_conn == NULL){ + efree(hashed_details); + php3_error(E_WARNING, "Out of memory"); + RETURN_FALSE; + } + + if (orlon(&db_conn->lda, db_conn->hda, user, + strlen(user), pwd, strlen(pwd), 0)) { + php3_error(E_WARNING, "Unable to connect to ORACLE (%s)", + ora_error(&db_conn->lda)); + if (persistent) + free(db_conn); + else + efree(db_conn); + efree(hashed_details); + RETURN_FALSE; + } + + db_conn->open = 1; + if (persistent){ + /*new_le.type = ORACLE_GLOBAL(php3_oracle_module).le_pconn; + new_le.ptr = db_conn;*/ + return_value->value.lval = + php3_plist_insert(db_conn, ORACLE_GLOBAL(php3_oracle_module).le_pconn); + new_index_ptr.ptr = (void *) return_value->value.lval; +#ifdef THREAD_SAFE + new_index_ptr.type = _php3_le_index_ptr(); +#else + new_index_ptr.type = le_index_ptr; +#endif + if (_php3_hash_update(plist,hashed_details,hashed_len + 1,(void *) &new_index_ptr, + sizeof(list_entry),NULL) == FAILURE) { + ologof(&db_conn->lda); + free(db_conn); + efree(hashed_details); + php3_error(E_WARNING, "Can't update hashed details list"); + RETURN_FALSE; + } + ORACLE_GLOBAL(php3_oracle_module).num_persistent++; + } else { + /* non persistent, simply add to list */ + return_value->value.lval = + php3_list_insert(db_conn, ORACLE_GLOBAL(php3_oracle_module).le_conn); + } + + ORACLE_GLOBAL(php3_oracle_module).num_links++; + + } else { + int type; + + /* the link is already in the persistent list */ +#ifdef THREAD_SAFE + if (index_ptr->type != _php3_le_index_ptr()) { +#else + if (index_ptr->type != le_index_ptr) { +#endif + efree(hashed_details); + php3_error(E_WARNING, "Oops, something went completly wrong"); + RETURN_FALSE; + } + id = (int) index_ptr->ptr; + db_conn = (oraConnection *)php3_plist_find(id, &type); + + if (db_conn && (type == ORACLE_GLOBAL(php3_oracle_module).le_conn || + type == ORACLE_GLOBAL(php3_oracle_module).le_pconn)){ + if(!_ora_ping(db_conn)) { + /* XXX Reinitialize lda, hda ? */ + if(orlon(&db_conn->lda, db_conn->hda, user, + strlen(user), pwd, strlen(pwd), 0)) { + php3_error(E_WARNING, "Unable to reconnect to ORACLE (%s)", + ora_error(&db_conn->lda)); + /* Delete list entry for this connection */ + php3_plist_delete(id); + /* Delete hashed list entry for this dead connection */ + _php3_hash_del(plist, hashed_details, hashed_len); + efree(hashed_details); + RETURN_FALSE; + } + } + return_value->value.lval = id; + } + } + efree(hashed_details); + return_value->type = IS_LONG; +} + +/* {{{ proto int ora_logoff(int connection) + Close an Oracle connection */ +void php3_Ora_Logoff(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + int type, ind; + oraConnection *conn; + pval *arg; + ORACLE_TLS_VARS; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(arg); + ind = (int)arg->value.lval; + + conn = (oraConnection *)php3_list_find(ind, &type); + if (!conn || (type != ORACLE_GLOBAL(php3_oracle_module).le_conn && + type != ORACLE_GLOBAL(php3_oracle_module).le_pconn)) { + return; + } + php3_list_delete(ind); +} +/* }}} */ + +/* {{{ proto int ora_open(int connection) + Open an Oracle cursor */ +void php3_Ora_Open(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + pval *arg; + oraConnection *conn = NULL; + oraCursor *cursor = NULL; + int conn_ind; + + if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + + conn_ind = arg->value.lval; + conn = ora_get_conn(list, conn_ind); + if (conn == NULL) { + RETURN_FALSE; + } + + if ((cursor = (oraCursor *)emalloc(sizeof(oraCursor))) == NULL){ + php3_error(E_WARNING, "Out of memory"); + RETURN_FALSE; + } + memset(cursor, 0, sizeof(oraCursor)); + if (oopen(&cursor->cda, &conn->lda, (text *) 0, -1, -1, (text *) 0, -1)) { + php3_error(E_WARNING, "Unable to open new cursor (%s)", + ora_error(&cursor->cda)); + efree(cursor); + RETURN_FALSE; + } + cursor->open = 1; + cursor->conn_ptr = conn; + RETURN_LONG(ora_add_cursor(list, cursor)); +} +/* }}} */ + +/* {{{ proto int ora_close(int cursor) + Close an Oracle cursor */ +void php3_Ora_Close(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + pval *arg; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(arg); + + ora_del_cursor(list, arg->value.lval); + RETVAL_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_commitoff(int connection) + Disable automatic commit */ +void php3_Ora_CommitOff(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + pval *arg; + oraConnection *conn; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + + conn = ora_get_conn(list, arg->value.lval); + if (conn == NULL) { + RETURN_FALSE; + } + if (ocof(&conn->lda)) { + php3_error(E_WARNING, "Unable to turn off auto-commit (%s)", + ora_error(&conn->lda)); + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_commiton(int connection) + Enable automatic commit */ +void php3_Ora_CommitOn(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + pval *arg; + oraConnection *conn; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + + if (!(conn = ora_get_conn(list, arg->value.lval))) { + RETURN_FALSE; + } + + if (ocon(&conn->lda)) { + php3_error(E_WARNING, "Unable to turn on auto-commit (%s)", + ora_error(&conn->lda)); + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_commit(int connection) + Commit an Oracle transaction */ +void php3_Ora_Commit(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + pval *arg; + oraConnection *conn; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + + conn = ora_get_conn(list, arg->value.lval); + if (conn == NULL) { + RETURN_FALSE; + } + if (ocom(&conn->lda)) { + php3_error(E_WARNING, "Unable to commit transaction (%s)", + ora_error(&conn->lda)); + RETURN_FALSE; + } + RETVAL_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_rollback(int connection) + Roll back an Oracle transaction */ +void php3_Ora_Rollback(INTERNAL_FUNCTION_PARAMETERS) +{ /* conn_index */ + pval *arg; + oraConnection *conn; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + + conn = ora_get_conn(list, arg->value.lval); + if (conn == NULL) { + RETURN_FALSE; + } + if (orol(&conn->lda)) { + php3_error(E_WARNING, "Unable to roll back transaction (%s)", + ora_error(&conn->lda)); + RETURN_FALSE; + } + RETVAL_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_parse(int cursor, string sql_statement [, int defer]) + Parse an Oracle SQL statement */ +void php3_Ora_Parse(INTERNAL_FUNCTION_PARAMETERS) +{ + /* cursor_ind, sql_statement [, defer] */ + int argc; + pval *argv[3]; + oraCursor *cursor; + sword defer = 0; + text *query; + + argc = ARG_COUNT(ht); + if ((argc != 2 && argc != 3) || getParametersArray(ht, argc, argv) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(argv[0]); + convert_to_string(argv[1]); + + if (argc == 3) { + convert_to_long(argv[2]); + if (argv[2]->value.lval != 0) { + defer = DEFER_PARSE; + } + } + + query = (text *) estrndup(argv[1]->value.str.val,argv[1]->value.str.len); + + if (query == NULL) { + php3_error(E_WARNING, "Invalid query"); + RETURN_FALSE; + } + if (!(cursor = ora_get_cursor(list, argv[0]->value.lval))){ + RETURN_FALSE; + } + + if (cursor->query) { + efree(cursor->query); + } + cursor->query = query; + cursor->fetched = 0; + if(cursor->params && cursor->nparams > 0){ + _php3_hash_destroy(cursor->params); + efree(cursor->params); + cursor->params = NULL; + cursor->nparams = 0; + } + + if (oparse(&cursor->cda, query, (sb4) - 1, defer, VERSION_7)) { + php3_error(E_WARNING, "Ora_Parse failed (%s)", + ora_error(&cursor->cda)); + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_bind(int cursor, string php_variable_name, string sql_parameter_name, int length [, int type]) + Bind a PHP variable to an Oracle parameter */ +void php3_Ora_Bind(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_ind, php_var_name, sql_var_name, data_len [, inout]*/ + /* inout: 0 = in/out, 1 = in, 2 = out */ + int argc; + pval *argv[5]; + oraParam *newparam, *paramptr; + oraCursor *cursor; + char *paramname; + + argc = ARG_COUNT(ht); + if (argc < 4 || argc > 5 || getParametersArray(ht, argc, argv) == FAILURE){ + WRONG_PARAM_COUNT; + } + convert_to_long(argv[0]); + convert_to_string(argv[1]); + convert_to_string(argv[2]); + convert_to_long(argv[3]); + + cursor = ora_get_cursor(list, argv[0]->value.lval); + if (cursor == NULL) { + php3_error(E_WARNING, "Invalid cursor index %d", + argv[0]->value.lval); + RETURN_FALSE; + } + + if(cursor->params == NULL){ + cursor->params = (HashTable *)emalloc(sizeof(HashTable)); + if (!cursor->params || + _php3_hash_init(cursor->params, 19, NULL, + NULL, 0) == + /* (void (*)(void *))pval_ora_param_destructor, 0) == */ + FAILURE){ + php3_error(E_ERROR, "Unable to initialize parameter list"); + RETURN_FALSE; + } + } + if((newparam = (oraParam *)emalloc(sizeof(oraParam))) == NULL){ + php3_error(E_WARNING, "Out of memory for parameter"); + RETURN_FALSE; + } + + if((paramname = estrndup(argv[1]->value.str.val, argv[1]->value.str.len)) == NULL){ + php3_error(E_WARNING, "Out of memory for parametername"); + efree(newparam); + RETURN_FALSE; + } + + if (_php3_hash_add(cursor->params, paramname, argv[1]->value.str.len + 1, newparam, sizeof(oraParam), (void **)¶mptr) == FAILURE) { + /* XXX _php3_hash_destroy */ + efree(paramname); + efree(newparam); + php3_error(E_ERROR, "Could not make parameter placeholder"); + RETURN_FALSE; + } + + efree(newparam); + efree(paramname); + + paramptr->progvl = argv[3]->value.lval + 1; + if(argc > 4){ + convert_to_long(argv[4]); + paramptr->type = (short)argv[4]->value.lval; + }else{ + paramptr->type = 0; + } + + if((paramptr->progv = (text *)emalloc(paramptr->progvl)) == NULL){ + php3_error(E_WARNING, "Out of memory for parameter value"); + RETURN_FALSE; + } + +/* XXX Maximum for progvl */ + paramptr->alen = paramptr->progvl; + if(obndra(&cursor->cda, argv[2]->value.str.val, -1, + (ub1 *)paramptr->progv, paramptr->progvl, SQLT_STR, + -1, 0, ¶mptr->alen, 0, 0, 0, 0, -1, -1)){ + php3_error(E_WARNING, "Ora_Bind failed (%s)", + ora_error(&cursor->cda)); + RETURN_FALSE; + } + + cursor->nparams++; + RETURN_TRUE; +} +/* }}} */ + +/* + XXX Make return values compatible with old module ? + */ +/* {{{ proto int ora_exec(int cursor) + Execute a parsed statement */ +void php3_Ora_Exec(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index */ + pval *arg; + oraCursor *cursor = NULL; + + if (getParameters(ht, 1, &arg) == FAILURE) + WRONG_PARAM_COUNT; + + convert_to_long(arg); + + if ((cursor = ora_get_cursor(list, arg->value.lval)) == NULL) { + RETURN_FALSE; + } + + if (cursor->cda.ft == FT_SELECT) { + if (ora_describe_define(cursor) < 0) { + /* error message is given by ora_describe_define() */ + RETURN_FALSE; + } + } + + if(cursor->nparams > 0){ + if(!ora_set_param_values(cursor, 0)){ + RETURN_FALSE; + } + } + + if (oexec(&cursor->cda)) { + php3_error(E_WARNING, "Ora_Exec failed (%s)", + ora_error(&cursor->cda)); + RETURN_FALSE; + } + + if(cursor->nparams > 0){ + if(!ora_set_param_values(cursor, 1)){ + RETURN_FALSE; + } + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_numcols(int cursor) + Returns the numbers of columns in a result */ +void php3_Ora_NumCols(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index */ + pval *arg; + oraCursor *cursor = NULL; + + if (getParameters(ht, 1, &arg) == FAILURE) + WRONG_PARAM_COUNT; + + convert_to_long(arg); + + if ((cursor = ora_get_cursor(list, arg->value.lval)) == NULL) { + RETURN_FALSE; + } + + RETURN_LONG(cursor->ncols); +} +/* }}} */ + +/* {{{ proto int ora_numrows(int cursor) + Returns the number of rows in a result */ +void php3_Ora_NumRows(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index */ + pval *arg; + oraCursor *cursor = NULL; + + if(getParameters(ht, 1, &arg) == FAILURE) + WRONG_PARAM_COUNT; + + convert_to_long(arg); + + if((cursor = ora_get_cursor(list, arg->value.lval)) == NULL) { + RETURN_FALSE; + } + + RETURN_LONG(cursor->cda.rpc); +} +/* }}} */ + +/* prepares/executes/fetches 1st row if avail*/ +/* {{{ proto int ora_do(int connection, int cursor) + Parse and execute a statement and fetch first result row */ +void php3_Ora_Do(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *argv[2]; + oraConnection *conn = NULL; + oraCursor *cursor = NULL; + text *query; + + if (ARG_COUNT(ht) != 2 || getParametersArray(ht, 2, argv) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(argv[0]); + convert_to_string(argv[1]); + + conn = ora_get_conn(list, argv[0]->value.lval); + if (conn == NULL) { + RETURN_FALSE; + } + + if ((cursor = (oraCursor *)emalloc(sizeof(oraCursor))) == NULL){ + php3_error(E_WARNING, "Out of memory"); + RETURN_FALSE; + } + + memset(cursor, 0, sizeof(oraCursor)); + + query = (text *) estrndup(argv[1]->value.str.val,argv[1]->value.str.len); + + if (query == NULL) { + php3_error(E_WARNING, "Invalid query in Ora_Do"); + RETURN_FALSE; + } + + cursor->query = query; + + if (oopen(&cursor->cda, &conn->lda, (text *) 0, -1, -1, (text *) 0, -1)) { + php3_error(E_WARNING, "Unable to open new cursor (%s)", + ora_error(&cursor->cda)); + efree(cursor); + RETURN_FALSE; + } + cursor->open = 1; + cursor->conn_ptr = conn; + + /* Prepare stmt */ + + if (oparse(&cursor->cda, query, (sb4) - 1, 1, VERSION_7)){ + php3_error(E_WARNING, "Ora_Do failed (%s)", + ora_error(&cursor->cda)); + _close_oracur(cursor); + RETURN_FALSE; + } + + /* Execute stmt (and fetch 1st row for selects) */ + if (cursor->cda.ft == FT_SELECT) { + if (ora_describe_define(cursor) < 0){ + /* error message is given by ora_describe_define() */ + _close_oracur(cursor); + RETURN_FALSE; + } + if (oexfet(&cursor->cda, 1, 0, 0)) { + php3_error(E_WARNING, "Ora_Do failed (%s)", + ora_error(&cursor->cda)); + _close_oracur(cursor); + RETURN_FALSE; + } + cursor->fetched = 1; + } else { + if (oexec(&cursor->cda)) { + php3_error(E_WARNING, "Ora_Do failed (%s)", + ora_error(&cursor->cda)); + _close_oracur(cursor); + RETURN_FALSE; + } + } + + RETURN_LONG(ora_add_cursor(list, cursor)); +} +/* }}} */ + +/* {{{ proto int ora_fetch(int cursor) + Fetch a row of result data from a cursor */ +void php3_Ora_Fetch(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index */ + pval *arg; + oraCursor *cursor; + + if (getParameters(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(arg); + + /* Find the cursor */ + if ((cursor = ora_get_cursor(list, arg->value.lval)) == NULL) { + RETURN_FALSE; + } + + if (cursor->ncols == 0){ + php3_error(E_WARNING, "No tuples available on this cursor"); + RETURN_FALSE; + } + + /* Get data from Oracle */ + if (ofetch(&cursor->cda)) { + if (cursor->cda.rc != NO_DATA_FOUND) { + php3_error(E_WARNING, "Ora_Fetch failed (%s)", + ora_error(&cursor->cda)); + } + RETURN_FALSE; + } + cursor->fetched++; + RETVAL_TRUE; +} +/* }}} */ + +/* {{{ proto int ora_fetchinto(int cursor, array result) + Fetch a row into the specified result array */ +void php3_Ora_FetchInto(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index, array ref */ + pval *arg1, *arr, tmp; + oraCursor *cursor; + ub4 ret_len; + int i; + + if (getParameters(ht, 2, &arg1, &arr) == FAILURE) { + WRONG_PARAM_COUNT; + } + + if (!ParameterPassedByReference(ht, 2)){ + php3_error(E_WARNING, "Array not passed by reference in call to ora_fetch_into()"); + RETURN_FALSE; + } + + convert_to_long(arg1); + + /* Find the cursor */ + if ((cursor = ora_get_cursor(list, arg1->value.lval)) == NULL) { + RETURN_FALSE; + } + + if (cursor->ncols == 0){ + php3_error(E_WARNING, "No tuples available on this cursor"); + RETURN_FALSE; + } + + if (arr->type != IS_ARRAY){ + if (array_init(arr) == FAILURE){ + php3_error(E_WARNING, "Can't convert to type Array"); + RETURN_FALSE; + } + } + + if (ofetch(&cursor->cda)) { + if (cursor->cda.rc != NO_DATA_FOUND) { + php3_error(E_WARNING, "Ora_Fetch_Into failed (%s)", + ora_error(&cursor->cda)); + } + RETURN_FALSE; + } + cursor->fetched++; + + for (i = 0; i < cursor->ncols; i++) { + tmp.type = IS_STRING; + tmp.value.str.len = 0; + + if (cursor->columns[i].col_retcode == 1405) { + continue; /* don't add anything for NULL columns */ + } else if (cursor->columns[i].col_retcode != 0 && + cursor->columns[i].col_retcode != 1406) { + /* So error fetching column. The most common is 1405, a NULL */ + /* was retreived. 1406 is ASCII or string buffer data was */ + /* truncated. The converted data from the database did not fit */ + /* into the buffer. Since we allocated the buffer to be large */ + /* enough, this should not occur. Anyway, we probably want to */ + /* return what we did get, in that case */ + RETURN_FALSE; + } else { + switch(cursor->columns[i].dbtype) { + case SQLT_LNG: + case SQLT_LBI: + /* XXX 64k max for LONG and LONG RAW */ + oflng(&cursor->cda, (sword)(i + 1), cursor->columns[i].buf, DB_SIZE, 1, + &ret_len, 0); + tmp.value.str.len = ret_len; + break; + default: + tmp.value.str.len = min(cursor->columns[i].col_retlen, + cursor->columns[i].dsize); + break; + } + tmp.value.str.val = estrndup(cursor->columns[i].buf, + tmp.value.str.len); + } + _php3_hash_index_update(arr->value.ht, i, (void *) &tmp, sizeof(pval), NULL); + } + + RETURN_LONG(cursor->ncols); +} +/* }}} */ + +/* {{{ proto string ora_columnname(int cursor, int column) + Get the name of an Oracle result column */ +void php3_Ora_ColumnName(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index, column_index */ + pval *argv[2]; + int cursor_ind; + oraCursor *cursor = NULL; + + if (ARG_COUNT(ht) != 2 || getParametersArray(ht, 2, argv) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(argv[0]); + + cursor_ind = argv[0]->value.lval; + /* Find the cursor */ + if ((cursor = ora_get_cursor(list, cursor_ind)) == NULL) { + RETURN_FALSE; + } + + convert_to_long(argv[1]); + + if (cursor->ncols == 0){ + php3_error(E_WARNING, "No tuples available at this cursor index"); + RETURN_FALSE; + } + + if (argv[1]->value.lval >= cursor->ncols){ + php3_error(E_WARNING, "Column index larger than number of columns"); + RETURN_FALSE; + } + + if (argv[1]->value.lval < 0){ + php3_error(E_WARNING, "Column numbering starts at 0"); + RETURN_FALSE; + } + + RETURN_STRINGL(cursor->columns[argv[1]->value.lval].cbuf, + cursor->columns[argv[1]->value.lval].cbufl,1); +} +/* }}} */ + +/* {{{ proto string ora_columntype(int cursor, int column) + Get the type of an Oracle result column */ +void php3_Ora_ColumnType(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index, column_index */ + pval *argv[2]; + int cursor_ind, colno; + oraCursor *cursor = NULL; + + if (ARG_COUNT(ht) != 2 || getParametersArray(ht, 2, argv) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(argv[0]); + /* don't convert the column index yet, it might be the column name */ + + cursor_ind = argv[0]->value.lval; + /* Find the cursor */ + if ((cursor = ora_get_cursor(list, cursor_ind)) == NULL) { + RETURN_FALSE; + } + + convert_to_long(argv[1]); + colno = argv[1]->value.lval; + + if (cursor->ncols == 0){ + php3_error(E_WARNING, "No tuples available at this cursor index"); + RETURN_FALSE; + } + + if (colno >= cursor->ncols){ + php3_error(E_WARNING, "Column index larger than number of columns"); + RETURN_FALSE; + } + + if (colno < 0){ + php3_error(E_WARNING, "Column numbering starts at 0"); + RETURN_FALSE; + } + + switch (cursor->columns[colno].dbtype) { + case SQLT_CHR: + RETURN_STRINGL("VARCHAR2", 8, 1); + case SQLT_VCS: + case SQLT_AVC: + RETURN_STRINGL("VARCHAR", 7, 1); + case SQLT_STR: + case SQLT_AFC: + RETURN_STRINGL("CHAR", 4, 1); + case SQLT_NUM: case SQLT_INT: + case SQLT_FLT: case SQLT_UIN: + RETURN_STRINGL("NUMBER", 6, 1); + case SQLT_LNG: + RETURN_STRINGL("LONG", 4, 1); + case SQLT_LBI: + RETURN_STRINGL("LONG RAW", 8, 1); + case SQLT_RID: + RETURN_STRINGL("ROWID", 5, 1); + case SQLT_DAT: + RETURN_STRINGL("DATE", 4, 1); +#ifdef SQLT_CUR + case SQLT_CUR: + RETURN_STRINGL("CURSOR", 6, 1); +#endif + default: + { + char numbuf[21]; + snprintf(numbuf, 20, "UNKNOWN(%d)", cursor->columns[colno].dbtype); + numbuf[20] = '\0'; + RETVAL_STRING(numbuf,1); + } + } +} +/* }}} */ + +/* {{{ proto int ora_columnsize(int cursor, int column) + Return the size of the column */ +void php3_Ora_ColumnSize(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index, column_index */ + pval *argv[2]; + int cursor_ind; + oraCursor *cursor = NULL; + + if (ARG_COUNT(ht) != 2 || getParametersArray(ht, 2, argv) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long(argv[0]); + + cursor_ind = argv[0]->value.lval; + /* Find the cursor */ + if ((cursor = ora_get_cursor(list, cursor_ind)) == NULL) { + RETURN_FALSE; + } + + convert_to_long(argv[1]); + + if (cursor->ncols == 0){ + php3_error(E_WARNING, "No tuples available at this cursor index"); + RETURN_FALSE; + } + + if (argv[1]->value.lval >= cursor->ncols){ + php3_error(E_WARNING, "Column index larger than number of columns"); + RETURN_FALSE; + } + + if (argv[1]->value.lval < 0){ + php3_error(E_WARNING, "Column numbering starts at 0"); + RETURN_FALSE; + } + + RETURN_LONG(cursor->columns[argv[1]->value.lval].dbsize); +} +/* }}} */ + +/* {{{ proto mixed ora_getcolumn(int cursor, int column) + Get data from a fetched row */ +void php3_Ora_GetColumn(INTERNAL_FUNCTION_PARAMETERS) +{ /* cursor_index, column_index */ + pval *argv[2]; + int colno; + oraCursor *cursor = NULL; + oraColumn *column = NULL; + sb2 type; + + if (ARG_COUNT(ht) != 2 || getParametersArray(ht, 2, argv) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(argv[0]); + + /* Find the cursor */ + if ((cursor = ora_get_cursor(list, argv[0]->value.lval)) == NULL) { + RETURN_FALSE; + } + + if (cursor->ncols == 0){ + php3_error(E_WARNING, "No tuples available at this cursor index"); + RETURN_FALSE; + } + + convert_to_long(argv[1]); + colno = argv[1]->value.lval; + + if (colno >= cursor->ncols){ + php3_error(E_WARNING, "Column index larger than number of columns"); + RETURN_FALSE; + } + + if (colno < 0){ + php3_error(E_WARNING, "Column numbering starts at 0"); + RETURN_FALSE; + } + + if (cursor->fetched == 0){ + if (ofetch(&cursor->cda)) { + if (cursor->cda.rc != NO_DATA_FOUND) { + php3_error(E_WARNING, "Ora_Fetch failed (%s)", + ora_error(&cursor->cda)); + } + RETURN_FALSE; + } + cursor->fetched++; + } + + column = &cursor->columns[colno]; + + type = column->dbtype; + + if (column->col_retcode != 0 && column->col_retcode != 1406) { + /* So error fetching column. The most common is 1405, a NULL + * was retreived. 1406 is ASCII or string buffer data was + * truncated. The converted data from the database did not fit + * into the buffer. Since we allocated the buffer to be large + * enough, this should not occur. Anyway, we probably want to + * return what we did get, in that case + */ + RETURN_FALSE; + } else { + switch(type) + { + case SQLT_CHR: + case SQLT_NUM: + case SQLT_INT: + case SQLT_FLT: + case SQLT_STR: + case SQLT_UIN: + case SQLT_AFC: + case SQLT_AVC: + case SQLT_DAT: + RETURN_STRINGL(column->buf, min(column->col_retlen, column->dsize), 1); + case SQLT_LNG: + case SQLT_LBI: + { + ub4 ret_len; + /* XXX 64k max for LONG and LONG RAW */ + oflng(&cursor->cda, (sword)(colno + 1), column->buf, DB_SIZE, 1, + &ret_len, 0); + RETURN_STRINGL(column->buf, ret_len, 1); + } + default: + php3_error(E_WARNING, + "Ora_GetColumn found invalid type (%d)", type); + RETURN_FALSE; + } + } +} +/* }}} */ + +/* {{{ proto string ora_error(int cursor_or_connection) + Get an Oracle error message */ +void php3_Ora_Error(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *arg; + oraCursor *cursor; + oraConnection *conn; + + if (ARG_COUNT(ht) != 1 || getParametersArray(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(arg); + if ((cursor = ora_get_cursor(list, arg->value.lval)) != NULL) { + return_value->type = IS_STRING; + return_value->value.str.val = ora_error(&cursor->cda); + return_value->value.str.len = strlen(return_value->value.str.val); + } else if ((conn = ora_get_conn(list, arg->value.lval)) != NULL) { + return_value->type = IS_STRING; + return_value->value.str.val = ora_error(&conn->lda); + return_value->value.str.len = strlen(return_value->value.str.val); + } +} +/* }}} */ + +/* {{{ proto int ora_errorcode(int cursor_or_connection) + Get an Oracle error code */ +void php3_Ora_ErrorCode(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *arg; + oraCursor *cursor; + oraConnection *conn; + + if (ARG_COUNT(ht) != 1 || getParametersArray(ht, 1, &arg) == FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(arg); + if ((cursor = ora_get_cursor(list, arg->value.lval)) != NULL) { + RETVAL_LONG(cursor->cda.rc); + } else if ((conn = ora_get_conn(list, arg->value.lval)) != NULL) { + RETURN_LONG(conn->lda.rc); + } +} +/* }}} */ + +void php3_info_oracle() +{ +#if !(WIN32|WINNT) + php3_printf("Oracle version: %s
\n" + "Compile-time ORACLE_HOME: %s
\n" + "Libraries used: %s", + PHP_ORACLE_VERSION, PHP_ORACLE_HOME, PHP_ORACLE_LIBS); +#endif +} + + +/* +** Functions internal to this module. +*/ + +static oraConnection * +ora_get_conn(HashTable *list, int ind) +{ + oraConnection *conn = NULL; + int type; + HashTable *plist; + ORACLE_TLS_VARS; + + plist = ORACLE_GLOBAL(php3_oracle_module).resource_plist; + + conn = (oraConnection *)php3_list_find(ind, &type); + if (conn && type == ORACLE_GLOBAL(php3_oracle_module).le_conn) + return conn; + + conn = (oraConnection *)php3_plist_find(ind, &type); + if (conn && type == ORACLE_GLOBAL(php3_oracle_module).le_pconn) + return conn; + + php3_error(E_WARNING,"Bad Oracle connection number (%d)", ind); + return NULL; +} + +int ora_add_cursor(HashTable *list, oraCursor *cursor) +{ + ORACLE_TLS_VARS; + return php3_list_insert(cursor, ORACLE_GLOBAL(php3_oracle_module).le_cursor); +} + +static oraCursor * +ora_get_cursor(HashTable *list, int ind) +{ + oraCursor *cursor; + int type; + ORACLE_TLS_VARS; + + cursor = php3_list_find(ind, &type); + if (!cursor || type != ORACLE_GLOBAL(php3_oracle_module).le_cursor) { + php3_error(E_WARNING, "Invalid cursor index %d", ind); + return NULL; + } + return cursor; +} + +void ora_del_cursor(HashTable *list, int ind) +{ + oraCursor *cursor; + int type; + ORACLE_TLS_VARS; + + cursor = (oraCursor *) php3_list_find(ind, &type); + if (!cursor || type != ORACLE_GLOBAL(php3_oracle_module).le_cursor) { + php3_error(E_WARNING,"Can't find cursor %d",ind); + return; + } + php3_list_delete(ind); +} + +static char * +ora_error(Cda_Def * cda) +{ + sword n, l; + text *errmsg; + + errmsg = (text *) emalloc(512); + n = oerhms(cda, cda->rc, errmsg, 400); + + /* remove the last newline */ + l = strlen(errmsg); + if (l < 400 && errmsg[l - 1] == '\n') { + errmsg[l - 1] = '\0'; + l--; + } + if (cda->fc > 0) { + strcat(errmsg, " -- while processing OCI function "); + strncat(errmsg, ora_func_tab[cda->fc], 75); /* 512 - 400 - 36 */ + } + return (char *) errmsg; +} + +static sword +ora_describe_define(oraCursor * cursor) +{ + long col = 0; + int i; + sb2 type; + sb4 dbsize; + + if (cursor == NULL) { + return -1; + } + + if (cursor->columns) { + for(i = 0; i < cursor->ncols; i++){ + if (cursor->columns[i].buf) + efree(cursor->columns[i].buf); + } + efree(cursor->columns); + } + + cursor->ncols = 0; + + while(1){ + if (odescr(&cursor->cda, (sword) cursor->ncols + 1, &dbsize, (sb2 *)0, (sb1 *)0, + (sb4 *)0, (sb4 *)0, (sb2 *)0, (sb2 *)0, (sb2 *)0)){ + if (cursor->cda.rc == VAR_NOT_IN_LIST) { + break; + } else { + php3_error(E_WARNING, "%s", ora_error(&cursor->cda)); + cursor->ncols = 0; + return -1; + } + } + cursor->ncols++; + } + + if (cursor->ncols > 0){ + cursor->columns = (oraColumn *) emalloc(sizeof(oraColumn) * cursor->ncols); + if (cursor->columns == NULL){ + php3_error(E_WARNING, "Out of memory"); + return -1; + } + } + + for(col = 0; col < cursor->ncols; col++){ + memset(&cursor->columns[col], 0, sizeof(oraColumn)); + cursor->columns[col].cbufl = ORANAMELEN; + + if (odescr(&cursor->cda, (sword)col + 1, &cursor->columns[col].dbsize, + &cursor->columns[col].dbtype, &cursor->columns[col].cbuf[0], + &cursor->columns[col].cbufl, &cursor->columns[col].dsize, + &cursor->columns[col].prec, &cursor->columns[col].scale, + &cursor->columns[col].nullok)) { + if (cursor->cda.rc == VAR_NOT_IN_LIST) { + break; + } else { + php3_error(E_WARNING, "%s", ora_error(&cursor->cda)); + return -1; + } + } + + cursor->columns[col].cbuf[cursor->columns[col].cbufl] = '\0'; + + switch (cursor->columns[col].dbtype) { + case SQLT_LBI: + cursor->columns[col].dsize = DB_SIZE; + type = SQLT_LBI; + break; + case SQLT_LNG: + cursor->columns[col].dsize = DB_SIZE; + default: + type = SQLT_STR; + break; + } + + if ((cursor->columns[col].buf = (ub1 *) emalloc(cursor->columns[col].dsize + 1)) == NULL){ + php3_error(E_WARNING, "Out of memory"); + return -1; + } + /* Define an output variable for the column */ + if (odefin(&cursor->cda, (sword)col + 1, cursor->columns[col].buf, + cursor->columns[col].dsize + 1, type, -1, &cursor->columns[col].indp, + (text *) 0, -1, -1, &cursor->columns[col].col_retlen, + &cursor->columns[col].col_retcode)) { + php3_error(E_WARNING, "%s", ora_error(&cursor->cda)); + return -1; + } + } + return 1; +} + +/* see oracle_hack.c */ +extern PHPAPI HashTable *php3i_get_symbol_table(void); + +int ora_set_param_values(oraCursor *cursor, int isout) +{ + char *paramname; + oraParam *param; + pval *pdata; + int i, len; +#if (WIN32|WINNT) + /* see oracle_hack.c */ + HashTable *symbol_table=php3i_get_symbol_table(); +#endif + _php3_hash_internal_pointer_reset(cursor->params); + + if(_php3_hash_num_elements(cursor->params) != cursor->nparams){ + php3_error(E_WARNING, "Mismatch in number of parameters"); + return 0; + } + + for(i = 0; i < cursor->nparams; i++, _php3_hash_move_forward(cursor->params)){ + if(_php3_hash_get_current_key(cursor->params, ¶mname, NULL) != HASH_KEY_IS_STRING){ + php3_error(E_WARNING, "Can't get parameter name"); + return 0; + } + if(_php3_hash_get_current_data(cursor->params, (void **)¶m) == FAILURE){ + php3_error(E_WARNING, "Can't get parameter data"); + efree(paramname); + return 0; + } + + if(isout){ + /* XXX param->alen + 1 ?? */ + if(param->type != 1 && param->alen > 0){ +#if (WIN32|WINNT) + /* see oracle_hack.c */ + { + pval var; + char *name=(paramname); + var.value.str.val = (param->progv); + var.value.str.len = (param->alen); + var.type = IS_STRING; + _php3_hash_update(symbol_table, name, strlen(name)+1, &var, sizeof(pval),NULL); + } +#else + SET_VAR_STRINGL(paramname, param->progv, param->alen); +#endif + } + efree(paramname); + continue; + }else if(param->type == 2){ + efree(paramname); + continue; + } + + /* FIXME Globals don't work in extensions on windows, have to do something + else here. See oracle_hack.c */ +#if (WIN32|WINNT) + if(_php3_hash_find(symbol_table, paramname, strlen(paramname) + 1, (void **)&pdata) == FAILURE){ + php3_error(E_WARNING, "Can't find variable for parameter"); + efree(paramname); + return 0; + } +#else + if(_php3_hash_find(&EG(symbol_table), paramname, strlen(paramname) + 1, (void **)&pdata) == FAILURE){ + php3_error(E_WARNING, "Can't find variable for parameter"); + efree(paramname); + return 0; + } +#endif + convert_to_string(pdata); + if(param->progvl <= pdata->value.str.len){ + php3_error(E_NOTICE, "Input value will be truncated"); + } + + len = min(param->progvl - 1, pdata->value.str.len); + strncpy(param->progv, pdata->value.str.val, len); + + param->progv[len] = '\0'; + efree(paramname); + } + return 1; + +} + +#endif /* HAVE_ORACLE */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/ext/oracle/oracle.h b/ext/oracle/oracle.h new file mode 100644 index 00000000000..74e9c4d7c06 --- /dev/null +++ b/ext/oracle/oracle.h @@ -0,0 +1,157 @@ + +#ifndef _PHP3_ORACLE_H +#define _PHP3_ORACLE_H + +#if HAVE_ORACLE + +#if (defined(__osf__) && defined(__alpha)) +# ifndef A_OSF +# define A_OSF +# endif +# ifndef OSF1 +# define OSF1 +# endif +# ifndef _INTRINSICS +# define _INTRINSICS +# endif +#endif /* osf alpha */ + +#include "oratypes.h" +#include "ocidfn.h" +#ifdef __STDC__ +#include "ociapr.h" +#endif + +extern php3_module_entry oracle_module_entry; +#define oracle_module_ptr &oracle_module_entry + +/* oparse flags */ +#define DEFER_PARSE 1 +#define NATIVE 1 +#define VERSION_7 2 + +#define ORANUMWIDTH 38 + +#if (defined(__osf__) && defined(__alpha)) || defined(CRAY) || defined(KSR) +#define HDA_SIZE 512 +#else +#define HDA_SIZE 256 +#endif + +#define ORAUIDLEN 32 +#define ORAPWLEN 32 +#define ORANAMELEN 32 +#define ORABUFLEN 2000 + +/* Some Oracle error codes */ +#define VAR_NOT_IN_LIST 1007 +#define NO_DATA_FOUND 1403 +#define NULL_VALUE_RETURNED 1405 + +/* Some SQL and OCI function codes */ +#define FT_INSERT 3 +#define FT_SELECT 4 +#define FT_UPDATE 5 +#define FT_DELETE 9 + +#define FC_OOPEN 14 + +typedef struct { + int open; + Lda_Def lda; + ub1 hda[HDA_SIZE]; +} oraConnection; + +typedef struct oraColumn { + sb4 dbsize; + sb2 dbtype; + text cbuf[ORANAMELEN+1]; + sb4 cbufl; + sb4 dsize; + sb2 prec; + sb2 scale; + sb2 nullok; + ub1 *buf; + sb2 indp; + ub2 col_retlen, col_retcode; +} oraColumn; + +typedef struct oraParam { + text *progv; + sword progvl; + sb2 type; + ub2 alen; +} oraParam; + +typedef struct oraCursor { + int open; + Cda_Def cda; + text *query; + HashTable *params; + int nparams; + oraColumn *columns; + int ncols; + int fetched; + oraConnection *conn_ptr; +} oraCursor; + +typedef struct { + char *defDB; + char *defUser; + char *defPW; + long allow_persistent; + long max_persistent; + long max_links; + long num_persistent; + long num_links; + int le_conn, le_pconn, le_cursor; + HashTable *resource_list; + HashTable *resource_plist; +} oracle_module; + +extern void php3_Ora_Bind(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Close(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Commit(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_CommitOff(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_CommitOn(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Do(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Error(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_ErrorCode(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Exec(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Fetch(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_FetchInto(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_ColumnType(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_ColumnName(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_ColumnSize(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_GetColumn(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_NumCols(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_NumRows(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Logoff(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Logon(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_PLogon(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Open(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Parse(INTERNAL_FUNCTION_PARAMETERS); +extern void php3_Ora_Rollback(INTERNAL_FUNCTION_PARAMETERS); +extern int php3_minit_oracle(INIT_FUNC_ARGS); +extern int php3_mshutdown_oracle(SHUTDOWN_FUNC_ARGS); +extern void php3_info_oracle(void); +extern int php3_rinit_oracle(INIT_FUNC_ARGS); + +#else + +#define oracle_module_ptr NULL + +#endif /* HAVE_ORACLE */ + +#endif /* _PHP3_ORACLE_H */ + +/* + * Local Variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + + + + diff --git a/ext/oracle/oracle_hack.c b/ext/oracle/oracle_hack.c new file mode 100644 index 00000000000..b3ec71bc773 --- /dev/null +++ b/ext/oracle/oracle_hack.c @@ -0,0 +1,24 @@ +/* + This file needs to be compiled in with php on windows so that the + oracle dll will work (and can be compiled). preferably, I would + like to see if there is another way accomplish what needs to be + done with the symbol_table in ora_set_param_values() in oracle.c. + This is just a quick hack to get this out. + + Shane +*/ + +#include "php.h" + +PHPAPI HashTable *php3i_get_symbol_table(void) { + TLS_VARS; + return &GLOBAL(symbol_table); +} + +/* This is becoming a general callback file, rather than an oracle hack + * file. Seems we need the following now for xml. */ + +PHPAPI HashTable *php3i_get_function_table(void) { + TLS_VARS; + return &GLOBAL(function_table); +} diff --git a/ext/oracle/php3_oci8.h b/ext/oracle/php3_oci8.h new file mode 100644 index 00000000000..eaf9addb0b7 --- /dev/null +++ b/ext/oracle/php3_oci8.h @@ -0,0 +1,190 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-1999 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundatbion; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Stig Sæther Bakken | + | | + | Initial work sponsored by Thies Arntzen of | + | Digital Collections, http://www.digicol.de/ | + +----------------------------------------------------------------------+ + */ + +/* $Id */ + +#if HAVE_OCI8 +# ifndef _PHP_OCI8_H +# define _PHP_OCI8_H +# endif + +# if (defined(__osf__) && defined(__alpha)) +# ifndef A_OSF +# define A_OSF +# endif +# ifndef OSF1 +# define OSF1 +# endif +# ifndef _INTRINSICS +# define _INTRINSICS +# endif +# endif /* osf alpha */ + +# include + +typedef struct { + int id; + int persistent; + char dbname[ 64 ]; + OCIError *pError; + OCIServer *pServer; +} oci8_server; + +typedef struct { + int id; + int persistent; + oci8_server *server; + OCIError *pError; + OCISession *pSession; +} oci8_session; + +typedef struct { + int id; + oci8_session *session; + OCISvcCtx *pServiceContext; + OCIError *pError; + HashTable *descriptors; + int descriptors_count; +} oci8_connection; + +typedef struct { + dvoid *ocidescr; + ub4 type; +} oci8_descriptor; + +typedef struct { + pval *pval; + text *name; + ub4 name_len; + ub4 type; + char *data; /* for pval cache */ +} oci8_define; + +typedef struct { + int id; + oci8_connection *conn; + OCIError *pError; + OCIStmt *pStmt; + text *last_query; + HashTable *columns; + int ncolumns; + HashTable *binds; + HashTable *defines; + int executed; +} oci8_statement; + +typedef struct { + OCIBind *pBind; + pval *value; + dvoid *descr; /* used for binding of LOBS etc */ + ub4 maxsize; + sb2 indicator; + ub2 retcode; +} oci8_bind; + +typedef struct { + oci8_statement *statement; + OCIDefine *pDefine; + char *name; + ub4 name_len; + ub2 type; + ub4 size4; + ub4 storage_size4; + ub2 size2; + sb2 indicator; + ub2 retcode; + ub4 rlen; + ub2 is_descr; + int descr; + oci8_descriptor *pdescr; + void *data; + oci8_define *define; +} oci8_out_column; + +typedef struct { + OCIError *pError; + char *default_username; + char *default_password; + char *default_dbname; + + long debug_mode; + + long allow_persistent; + long max_persistent; + long max_links; + long num_persistent; + long num_links; + + int le_conn; /* active connections */ + int le_stmt; /* active statements */ + + int le_server; /* server-handles */ + int le_pserver; /* pesistent server-handles */ + + int le_session; /* session-handles */ + int le_psession;/* pesistent session-handles */ + + OCIEnv *pEnv; +} oci8_module; + +extern php3_module_entry oci8_module_entry; +# define oci8_module_ptr &oci8_module_entry + +# define OCI8_MAX_NAME_LEN 64 +# define OCI8_MAX_DATA_SIZE 2097152 /* two megs */ + +/* this one has to be changed to include persistent connections as well */ +# define OCI8_SERVER_TYPE(x) (((x)==OCI8_GLOBAL(php3_oci8_module).le_server) || ((x)==OCI8_GLOBAL(php3_oci8_module).le_pserver)) +# define OCI8_SESSION_TYPE(x) (((x)==OCI8_GLOBAL(php3_oci8_module).le_session) || ((x)==OCI8_GLOBAL(php3_oci8_module).le_psession)) + +# define OCI8_CONN_TYPE(x) ((x)==OCI8_GLOBAL(php3_oci8_module).le_conn) +# define OCI8_STMT_TYPE(x) ((x)==OCI8_GLOBAL(php3_oci8_module).le_stmt) + +# define RETURN_OUT_OF_MEMORY \ + php3_error(E_WARNING, "Out of memory");\ + RETURN_FALSE +# define OCI8_FAIL(c,f,r) \ + php3i_oci8_error((c)->pError,(f),(r));\ + RETURN_FALSE + +#else /* !HAVE_OCI8 */ + +# define oci8_module_ptr NULL + +#endif /* HAVE_OCI8 */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/ext/oracle/setup.stub b/ext/oracle/setup.stub new file mode 100644 index 00000000000..d49e64d13a3 --- /dev/null +++ b/ext/oracle/setup.stub @@ -0,0 +1,9 @@ +# $Source$ +# $Id$ + +define_option with-oracle 'Oracle support?' yesnodir \ + "no $oradir Oracle home" \ +' Whether to build PHP with Oracle support. Has been confirmed to\n + work with Oracle versions 7.0 to 7.3. If you have not set up your\n + Oracle environment, enter what $ORACLE_HOME is usually set to here.\n + More info about Oracle can be found at http://www.oracle.com/.' diff --git a/internal_functions.c b/internal_functions.c index c75fe2ec4e5..456dd93f758 100644 --- a/internal_functions.c +++ b/internal_functions.c @@ -51,9 +51,9 @@ #include "functions/php3_ldap.h" #include "ext/mysql/php3_mysql.h" #include "functions/php3_bcmath.h" -#include "functions/php3_msql.h" -#include "functions/php3_oci8.h" -#include "functions/oracle.h" +#include "ext/msql/php3_msql.h" +#include "ext/oracle/php3_oci8.h" +#include "ext/oracle/oracle.h" #include "functions/php3_pgsql.h" #include "functions/php3_sybase.h" #include "functions/php3_sybase-ct.h" @@ -62,7 +62,7 @@ #include "functions/head.h" #include "functions/post.h" #include "functions/hw.h" -#include "functions/filepro.h" +#include "ext/filepro/filepro.h" #include "functions/db.h" #include "dl/snmp/php3_snmp.h" #include "functions/php3_zlib.h" @@ -73,7 +73,7 @@ #include "functions/php3_fdf.h" #include "functions/php3_sysvsem.h" #include "functions/php3_sysvshm.h" -#include "functions/php3_dav.h" +#include "ext/dav/php3_dav.h" unsigned char first_arg_force_ref[] = { 1, BYREF_FORCE }; unsigned char first_arg_allow_ref[] = { 1, BYREF_ALLOW }; diff --git a/setup b/setup index ae87062165a..e17ed3ac56c 100644 --- a/setup +++ b/setup @@ -239,13 +239,6 @@ for stub in ext/*/setup.stub; do test -f $stub && . $stub done -define_option with-oracle 'Oracle support?' yesnodir \ - "no $oradir Oracle home" \ -' Whether to build PHP with Oracle support. Has been confirmed to\n - work with Oracle versions 7.0 to 7.3. If you have not set up your\n - Oracle environment, enter what $ORACLE_HOME is usually set to here.\n - More info about Oracle can be found at http://www.oracle.com/.' - define_option with-sybase 'Sybase support?' yesnodir \ 'no /home/sybase Sybase install' \ ' Whether to build PHP with Sybase support (DBLib only).\n @@ -255,18 +248,6 @@ define_option with-sybase-ct 'Sybase-CT support?' yesnodir \ 'no /home/sybase Sybase-CT install' \ ' Whether to build PHP with Sybase-CT support.' -define_option with-mysql 'MySQL support?' yesnodir \ - 'no /usr/local MySQL install' \ -' Whether to build PHP with MySQL support.\n - More info about MySQL can be found at http://www.tcx.se/.' - -define_option with-msql 'mSQL support?' yesnodir \ - 'no /usr/local/Hughes mSQL install' \ -' Whether to build PHP with mSQL support. PHP supports both mSQL 1.0 and\n - mSQL 2.0. However, if you build PHP with mSQL 1.0 libraries, you will\n - only be able to access mSQL 1.0 databases, ditto for mSQL 2.0.\n - More info about mSQL can be found at http://www.hughes.com.au/.' - define_option with-pgsql 'PostgreSQL support?' yesnodir \ 'no /usr/local/pgsql PostgreSQL base install' \ ' Whether to build PHP with PostgreSQL support.\n @@ -301,9 +282,6 @@ define_option with-imap 'IMAP support?' yesnodir \ support.\n More information about LDAP can be found in RFC1777 and RFC1778.' -define_option with-filepro 'filePro support? ' yesno no \ -' Whether to use the bundled filePro library. Read-access only.' - define_option with-pdflib 'pdflib 0.6 support? ' yesnodir \ 'no /usr/local pdflib install' \ ' Whether to use the pdflib support to write .pdf-files.\n