initial commit

This commit is contained in:
Chris Sewell
2012-11-28 03:55:08 -05:00
parent 7adb399b2e
commit cf140a2e97
3247 changed files with 492437 additions and 0 deletions

View File

@ -0,0 +1,398 @@
<?php
/**
* $Id: OCI8Connection.php,v 1.18 2005/10/17 19:03:51 dlawson_mi Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/Connection.php';
require_once 'creole/common/ConnectionCommon.php';
include_once 'creole/drivers/oracle/OCI8ResultSet.php';
/**
* Oracle implementation of Connection.
*
* @author David Giffin <david@giffin.org>
* @author Hans Lellelid <hans@xmpl.org>
* @author Stig Bakken <ssb@fast.no>
* @author Lukas Smith
* @version $Revision: 1.18 $
* @package creole.drivers.oracle
*/
class OCI8Connection extends ConnectionCommon implements Connection
{
protected $lastStmt = null;
/**
* Auto commit mode for oci_execute
* @var int
*/
protected $execMode = OCI_COMMIT_ON_SUCCESS;
/**
* Connect to a database and log in as the specified user.
*
* @param array $dsn The data source hash.
* @param int $flags Any connection flags.
* @access public
* @throws SQLException
* @return void
*/
function connect( $dsninfo, $flags = 0 )
{
if ( !extension_loaded( 'oci8' ) )
{
throw new SQLException( 'oci8 extension not loaded' );
}
$this->dsn = $dsninfo;
$this->flags = $flags;
$persistent =
( $flags & Creole::PERSISTENT === Creole::PERSISTENT );
$user = $dsninfo[ 'username' ];
$pw = $dsninfo[ 'password' ];
$hostspec = $dsninfo[ 'hostspec' ];
$port = $dsninfo[ 'port' ];
$db = $dsninfo[ 'database' ];
$connect_function = ( $persistent )
? 'oci_pconnect'
: 'oci_connect';
$encoding = !empty($dsninfo['encoding']) ? $dsninfo['encoding'] : null;
@ini_set( 'track_errors', true );
if ( $hostspec && $port )
{
$hostspec .= ':' . $port;
}
if ( $db && $hostspec && $user && $pw )
{
$conn = @$connect_function( $user, $pw, "//$hostspec/$db", $encoding);
}
elseif ( $hostspec && $user && $pw )
{
$conn = @$connect_function( $user, $pw, $hostspec, $encoding );
}
elseif ( $user || $pw )
{
$conn = @$connect_function( $user, $pw, null, $encoding );
}
else
{
$conn = false;
}
@ini_restore( 'track_errors' );
if ( $conn == false )
{
$error = oci_error();
$error = ( is_array( $error ) )
? $error[ 'message' ]
: null;
throw new SQLException( 'connect failed', $error );
}
$this->dblink = $conn;
//connected ok, need to set a few environment settings
//please note, if this is changed, the function setTimestamp and setDate in OCI8PreparedStatement.php
//must be changed to match
$sql = "ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'";
$this->executeQuery($sql);
}
/**
* @see Connection::disconnect()
*/
function close()
{
$ret = @oci_close( $this->dblink );
$this->dblink = null;
return $ret;
}
/**
* @see Connection::executeQuery()
*/
function executeQuery( $sql, $fetchmode = null )
{
$this->lastQuery = $sql;
// $result = @oci_parse( $this->dblink, $sql );
$result = oci_parse( $this->dblink, $sql );
if ( ! $result )
{
throw new SQLException( 'Unable to prepare query'
, $this->nativeError()
, $sql
);
}
$success = oci_execute( $result, $this->execMode );
if ( ! $success )
{
throw new SQLException( 'Unable to execute query'
, $this->nativeError( $result )
, $sql
);
}
return new OCI8ResultSet( $this, $result, $fetchmode );
}
/**
* @see Connection::simpleUpdate()
*/
function executeUpdate( $sql )
{
$this->lastQuery = $sql;
$statement = oci_parse( $this->dblink, $sql );
if ( ! $statement )
{
throw new SQLException( 'Unable to prepare update'
, $this->nativeError()
, $sql
);
}
$success = oci_execute( $statement, $this->execMode );
if ( ! $success )
{
throw new SQLException( 'Unable to execute update'
, $this->nativeError( $statement )
, $sql
);
}
$this->lastStmt = $statement;
return oci_num_rows( $statement );
}
/**
* Start a database transaction.
* @throws SQLException
* @return void
*/
protected function beginTrans()
{
$this->execMode = OCI_DEFAULT;
}
/**
* Commit the current transaction.
* @throws SQLException
* @return void
*/
protected function commitTrans()
{
$result = oci_commit( $this->dblink );
if ( ! $result )
{
throw new SQLException( 'Unable to commit transaction'
, $this->nativeError()
);
}
$this->execMode = OCI_COMMIT_ON_SUCCESS;
}
/**
* Roll back ( undo ) the current transaction.
* @throws SQLException
* @return void
*/
protected function rollbackTrans()
{
$result = oci_rollback( $this->dblink );
if ( ! $result )
{
throw new SQLException( 'Unable to rollback transaction'
, $this->nativeError()
);
}
$this->execMode = OCI_COMMIT_ON_SUCCESS;
}
/**
* Gets the number of rows affected by the data manipulation
* query.
*
* @return int Number of rows affected by the last query.
* @todo -cOCI8Connection Figure out whether getUpdateCount() should throw exception on error or just return 0.
*/
function getUpdateCount()
{
if ( ! $this->lastStmt )
{
return 0;
}
$result = oci_num_rows( $this->lastStmt );
if ( $result === false )
{
throw new SQLException( 'Update count failed'
, $this->nativeError( $this->lastStmt )
);
}
return $result;
}
/**
* Build Oracle-style query with limit or offset.
* If the original SQL is in variable: query then the requlting
* SQL looks like this:
* <pre>
* SELECT B.* FROM (
* SELECT A.*, rownum as TORQUE$ROWNUM FROM (
* query
* ) A
* ) B WHERE B.TORQUE$ROWNUM > offset AND B.TORQUE$ROWNUM
* <= offset + limit
* </pre>
*
* @param string &$sql the query
* @param int $offset
* @param int $limit
* @return void ( $sql parameter is currently manipulated directly )
*/
public function applyLimit( &$sql, $offset, $limit )
{
$sql =
'SELECT B.* FROM ( '
. 'SELECT A.*, rownum AS CREOLE$ROWNUM FROM ( '
. $sql
. ' ) A '
. ' ) B WHERE ';
if ( $offset > 0 )
{
$sql .= ' B.CREOLE$ROWNUM > ' . $offset;
if ( $limit > 0 )
{
$sql .= ' AND B.CREOLE$ROWNUM <= '
. ( $offset + $limit );
}
}
else
{
$sql .= ' B.CREOLE$ROWNUM <= ' . $limit;
}
}
/**
* Get the native Oracle Error Message as a string.
*
* @param string $msg The Internal Error Message
* @param mixed $errno The Oracle Error resource
*/
public function nativeError( $result = null )
{
if ( $result !== null )
{
$error = oci_error( $result );
}
else
{
$error = oci_error( $this->dblink );
}
return $error[ 'code' ] . ': ' . $error[ 'message' ];
}
/**
* @see Connection::getDatabaseInfo()
*/
public function getDatabaseInfo()
{
require_once 'creole/drivers/oracle/metadata/OCI8DatabaseInfo.php';
return new OCI8DatabaseInfo( $this );
}
/**
* @see Connection::getIdGenerator()
*/
public function getIdGenerator()
{
require_once 'creole/drivers/oracle/OCI8IdGenerator.php';
return new OCI8IdGenerator( $this );
}
/**
* Oracle supports native prepared statements, but the oci_parse call
* is actually called by the OCI8PreparedStatement class because
* some additional SQL processing may be necessary ( e.g. to apply limit ).
* @see OCI8PreparedStatement::executeQuery()
* @see OCI8PreparedStatement::executeUpdate()
* @see Connection::prepareStatement()
*/
public function prepareStatement( $sql )
{
require_once 'creole/drivers/oracle/OCI8PreparedStatement.php';
return new OCI8PreparedStatement( $this, $sql );
}
/**
* @see Connection::prepareCall()
*/
public function prepareCall( $sql )
{
throw new SQLException( 'Oracle driver does not yet support stored procedures using CallableStatement.' );
}
/**
* @see Connection::createStatement()
*/
public function createStatement()
{
require_once 'creole/drivers/oracle/OCI8Statement.php';
return new OCI8Statement( $this );
}
}

View File

@ -0,0 +1,65 @@
<?php
require_once 'creole/IdGenerator.php';
/**
* Oracle (OCI8) IdGenerator implimenation.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.5 $
* @package creole.drivers.oracle
*/
class OCI8IdGenerator implements IdGenerator {
/** Connection object that instantiated this class */
private $conn;
/**
* Creates a new IdGenerator class, saves passed connection for use
* later by getId() method.
* @param Connection $conn
*/
public function __construct(Connection $conn)
{
$this->conn = $conn;
}
/**
* @see IdGenerator::isBeforeInsert()
*/
public function isBeforeInsert()
{
return true;
}
/**
* @see IdGenerator::isAfterInsert()
*/
public function isAfterInsert()
{
return false;
}
/**
* @see IdGenerator::getIdMethod()
*/
public function getIdMethod()
{
return self::SEQUENCE;
}
/**
* @see IdGenerator::getId()
*/
public function getId($name = null)
{
if ($name === null) {
throw new SQLException("You must specify the sequence name when calling getId() method.");
}
$rs = $this->conn->executeQuery("select " . $name . ".nextval from dual", ResultSet::FETCHMODE_NUM);
$rs->next();
return $rs->getInt(1);
}
}

View File

@ -0,0 +1,424 @@
<?php
/*
* $Id: OCI8PreparedStatement.php,v 1.26 2006/01/30 21:32:05 sethr Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/PreparedStatement.php';
require_once 'creole/common/PreparedStatementCommon.php';
/**
* Oracle (OCI8) implementation of PreparedStatement.
*
* @author David Giffin <david@giffin.org>
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.26 $
* @package creole.drivers.oracle
*/
class OCI8PreparedStatement extends PreparedStatementCommon implements PreparedStatement {
/**
* Descriptor holders for LOB values.
* There are other types of descriptors, but we need to keep
* them separate, because we need to execute the save()/savefile() method
* on lob descriptors.
* @var array object from oci_new_descriptor
*/
private $lobDescriptors = array();
/**
* Hold any Blob/Clob data.
* These can be matched (by key) to descriptors in $lobDescriptors.
* @var array Lob[]
*/
private $lobs = array();
/**
* Array to store the columns in an insert or update statement.
* This is necessary for the proper handling of lob variables
* @var arrary columns[]
*/
private $columns = array();
/**
* If the statement is set, free it.
* @see PreparedStatement::close()
*/
function close()
{
if (isset($this->stmt))
@oci_free_statement($this->stmt);
}
/**
* Nothing to do - since oci_bind is used to insert data, no escaping is needed
* @param string $str
* @return string
*/
protected function escape($str)
{
return $str;
}
/**
* Executes the SQL query in this PreparedStatement object and returns the resultset generated by the query.
* @param mixed $p1 Either (array) Parameters that will be set using PreparedStatement::set() before query is executed or (int) fetchmode.
* @param int $fetchmode The mode to use when fetching the results (e.g. ResultSet::FETCHMODE_NUM, ResultSet::FETCHMODE_ASSOC).
* @return ResultSet
* @throws SQLException if a database access error occurs.
*/
public function executeQuery($p1 = null, $fetchmode = null)
{
$params = null;
if ($fetchmode !== null) {
$params = $p1;
} elseif ($p1 !== null) {
if (is_array($p1)) $params = $p1;
else $fetchmode = $p1;
}
if ($params) {
for($i=0,$cnt=count($params); $i < $cnt; $i++) {
$this->set($i+1, $params[$i]);
}
}
$this->updateCount = null; // reset
$sql = $this->sqlToOracleBindVars($this->sql);
if ($this->limit > 0 || $this->offset > 0) {
$this->conn->applyLimit($sql, $this->offset, $this->limit);
}
$result = oci_parse($this->conn->getResource(), $sql);
if (!$result) {
throw new SQLException("Unable to prepare query", $this->conn->nativeError(), $this->sqlToOracleBindVars($this->sql));
}
// bind all variables
$this->bindVars($result);
$success = oci_execute($result, OCI_DEFAULT);
if (!$success) {
throw new SQLException("Unable to execute query", $this->conn->nativeError($result), $this->sqlToOracleBindVars($this->sql));
}
$this->resultSet = new OCI8ResultSet($this->conn, $result, $fetchmode);
return $this->resultSet;
}
/**
* Executes the SQL INSERT, UPDATE, or DELETE statement in this PreparedStatement object.
*
* @param array $params Parameters that will be set using PreparedStatement::set() before query is executed.
* @return int Number of affected rows (or 0 for drivers that return nothing).
* @throws SQLException if a database access error occurs.
*/
public function executeUpdate($params = null)
{
if ($params) {
for($i=0,$cnt=count($params); $i < $cnt; $i++) {
$this->set($i+1, $params[$i]);
}
}
if($this->resultSet) $this->resultSet->close();
$this->resultSet = null; // reset
$stmt = oci_parse($this->conn->getResource(), $this->sqlToOracleBindVars($this->sql));
if (!$stmt) {
throw new SQLException("Unable to prepare update", $this->conn->nativeError(), $this->sqlToOracleBindVars($this->sql));
}
// bind all variables
$this->bindVars($stmt);
// Even if autocommit is on, delay commit until after LOBS have been saved
$success = oci_execute($stmt, OCI_DEFAULT);
if (!$success) {
throw new SQLException("Unable to execute update", $this->conn->nativeError($stmt), $this->sqlToOracleBindVars($this->sql));
}
// save data in any LOB descriptors, then free them
foreach($this->lobDescriptors as $paramIndex => $lobster) {
$lob = $this->lobs[$paramIndex]; // corresponding Blob/Clob
if ($lob->isFromFile()) {
$success = $lobster->savefile($lob->getInputFile());
} else {
$success = $lobster->save($lob->getContents());
}
if (!$success) {
$lobster->free();
throw new SQLException("Error saving lob bound to " . $paramIndex);
}
$lobster->free();
}
if ($this->conn->getAutoCommit()) {
oci_commit($this->conn->getResource()); // perform deferred commit
}
$this->updateCount = @oci_num_rows($stmt);
return $this->updateCount;
}
/**
* Performs the actual binding of variables using oci_bind_by_name().
*
* This may seem like useless overhead, but the reason why calls to oci_bind_by_name()
* are not performed in the set*() methods is that it is possible that the SQL will
* need to be modified -- e.g. by a setLimit() call -- and re-prepared. We cannot assume
* that the statement has been prepared when the set*() calls are invoked. This also means,
* therefore, that the set*() calls will not throw exceptions; all exceptions will be thrown
* when the statement is prepared.
*
* @param resource $stmt The statement result of oci_parse to use for binding.
* @return void
*/
private function bindVars($stmt)
{
foreach ($this->boundInVars as $idx => $val) {
$idxName = ":var" . $idx;
if (!oci_bind_by_name($stmt, $idxName, $this->boundInVars[$idx], -1)) {
throw new SQLException("Erorr binding value to placeholder " . $idx);
}
} // foreach
foreach ($this->lobs as $idx => $val) {
$idxName = ":var" . $idx;
if (class_exists('Blob') && $val instanceof Blob){
if (!oci_bind_by_name($stmt, $idxName, $this->lobDescriptors[$idx], -1, OCI_B_BLOB))
throw new SQLException("Erorr binding blob to placeholder " . $idx);
} elseif (class_exists('Clob') && $val instanceof Clob){
if (!oci_bind_by_name($stmt, $idxName, $this->lobDescriptors[$idx], -1, OCI_B_CLOB))
throw new SQLException("Erorr binding clob to placeholder " . $idx);
}
} // foreach
}
/**
* Convert a Propel SQL into Oracle SQL
*
* Look for all of the '?' and replace with ":varX"
*
* @param string $sql SQL in Propel native format
* @return string SQL in Oracle Bind Var format
* @todo -cOCI8PreparedStatement Consider changing this implementation to use the fact that we
* already know where all the '?' chars are (in $positions array).
*/
private function sqlToOracleBindVars($sql)
{
$out = "";
$in_literal = 0;
$idxNum = 1;
for ($i = 0; $i < strlen($sql); $i++) {
$char = $sql[$i];
if (strcmp($char,"'")==0) {
$in_literal = ~$in_literal;
}
if (strcmp($char,"?")==0 && !$in_literal) {
if (array_key_exists($idxNum, $this->lobs)){
if (class_exists('Blob') && ($this->lobs[$idxNum] instanceof Blob))
$out .= "empty_blob()";
if (class_exists('Clob') && ($this->lobs[$idxNum] instanceof Clob))
$out .= "empty_clob()";
} else
$out .= ":var" . $idxNum;
$idxNum++;
} else {
$out .= $char;
}
}
if (isset($this->lobs) && !empty($this->lobs)) {
$this->setColumnArray();
$retstmt = " Returning ";
$collist = "";
$bindlist = "";
foreach ($this->lobs as $idx=>$val) {
$idxName = ":var" . $idx;
if ((class_exists('Blob') && $val instanceof Blob) || (class_exists('Clob') && $val instanceof Clob)) {
//the columns array starts at zero instead of 1 like the lobs array
$collist .= $this->columns[$idx-1] . ",";
$bindlist .= $idxName . ",";
}
}
if (!empty($collist))
$out .= $retstmt . rtrim($collist, ",") . " into " . rtrim($bindlist, ",");
}
return $out;
}
/**
* @param string $paramIndex
* @param mixed $blob Blob object or string containing data.
* @return void
*/
function setBlob($paramIndex, $blob)
{
require_once 'creole/util/Blob.php';
if (!($blob instanceof Blob)) {
$b = new Blob();
$b->setContents($blob);
$blob = $b;
}
$this->lobDescriptors[$paramIndex] = oci_new_descriptor($this->conn->getResource(), OCI_D_LOB);
$this->lobs[$paramIndex] = $blob;
}
/**
* @param string $paramIndex
* @param mixed $clob Clob object or string containing data.
* @return void
*/
function setClob($paramIndex, $clob)
{
require_once 'creole/util/Clob.php';
if (!($clob instanceof Clob)) {
$c = new Clob();
$c->setContents($clob);
$clob = $c;
}
$this->lobDescriptors[$paramIndex] = oci_new_descriptor($this->conn->getResource(), OCI_D_LOB);
$this->lobs[$paramIndex] = $clob;
}
/**
* Since bind variables in oracle have no special characters, this setString method differs from the
* common one in that it does not single quote strings.
*
* @param int $paramIndex
* @param string $value
* @return void
*/
function setString($paramIndex, $value)
{
if ($value === null) {
$this->setNull($paramIndex);
} else {
// it's ok to have a fatal error here, IMO, if object doesn't have
// __toString() and is being passed to this method.
if ( is_object ( $value ) ) {
$this->boundInVars[$paramIndex] = $value->__toString();
} else {
$this->boundInVars[$paramIndex] = (string)$value;
}
}
}
/**
* Copied this function from common/PreparedStatement.php and modified to work with Oracle
* Please note the format used with date() matches that of NLS_DATE_FORMAT set in
* OCI8Connection.php
*
* @param int $paramIndex
* @param string $value
* @return void
*/
function setTimestamp($paramIndex, $value)
{
if ($value === null) {
$this->setNull($paramIndex);
} else {
if (is_numeric($value)) $value = date('Y-m-d H:i:s', $value);
elseif (is_object($value)) $value = date('Y-m-d H:i:s', $value->getTime());
$this->boundInVars[$paramIndex] = $value;
}
}
/**
* Please note the format used with date() matches that of NLS_DATE_FORMAT set in
* OCI8Connection.php
*
* @param int $paramIndex
* @param string $value
* @return void
*/
function setDate($paramIndex, $value)
{
if ($value === null) {
$this->setNull($paramIndex);
} else {
if (is_numeric($value)) $value = date("Y-m-d", $value);
elseif (is_object($value)) $value = date("Y-m-d", $value->getTime());
$this->boundInVars[$paramIndex] = $value;
}
}
/**
* In order to send lob data (clob/blob) to the Oracle data base, the
* sqlToOracleBindVars function needs to have an ordered list of the
* columns being addressed in the sql statement.
* Since only insert and update statements require special handling,
* there are two ways to find the columns:
* 1) find the first set of () and parse out the columns names based on
* the token ','
* 2) find all the text strings to the left of the equal signs.
*
* @param void
* @return void
*/
private function setColumnArray()
{
$this->columns = array();
//handle the simple insert case first
if(strtoupper(substr($this->sql, 0, 6)) == 'INSERT') {
$firstPos = strpos($this->sql, '(');
$secPos = strpos($this->sql, ')');
$collist = substr($this->sql, $firstPos + 1, $secPos - $firstPos - 1);
$this->columns = explode(',', $collist);
}
if (strtoupper(substr($this->sql, 0, 6)) == 'UPDATE') {
//handle more complex update case
//first get the string setup so we can explode based on '=?'
//second split results from previous action based on ' '
// the last token from this should be a column name
$tmp = $this->sql;
$tmp = str_replace(" =", "=", $this->sql);
$tmp = str_replace("= ", "=", $tmp);
$tmp = str_replace(",", " ", $tmp);
$stage1 = explode("=?",$tmp);
foreach($stage1 as $chunk) {
$stage2 = explode(' ', $chunk);
$this->columns[count($this->columns)] = $stage2[count($stage2) - 1];
}
}
}
/**
* @param int $paramIndex
* @return void
*/
function setNull($paramIndex)
{
$this->boundInVars[$paramIndex] = '';
}
}

View File

@ -0,0 +1,131 @@
<?php
/*
* $Id: OCI8ResultSet.php,v 1.13 2006/01/17 19:44:40 hlellelid Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/ResultSet.php';
require_once 'creole/common/ResultSetCommon.php';
/**
* Oracle (OCI8) implementation of ResultSet class.
*
* @author David Giffin <david@giffin.org>
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.13 $
* @package creole.drivers.oracle
*/
class OCI8ResultSet extends ResultSetCommon implements ResultSet
{
/**
* @see ResultSet::seek()
*/
function seek($rownum)
{
if ( $rownum < $this->cursorPos )
{
// this will effectively disable previous(), first() and some calls to relative() or absolute()
throw new SQLException( 'Oracle ResultSet is FORWARD-ONLY' );
}
// Oracle has no seek function imulate it here
while ( $this->cursorPos < $rownum )
{
$this->next();
}
$this->cursorPos = $rownum;
return true;
}
/**
* @see ResultSet::next()
*/
function next()
{
// no specific result position available
// Returns an array, which corresponds to the next result row or FALSE
// in case of error or there is no more rows in the result.
$this->fields = oci_fetch_array( $this->result
, $this->fetchmode
+ OCI_RETURN_NULLS
+ OCI_RETURN_LOBS
);
if ( ! $this->fields )
{
// grab error via array
$error = oci_error( $this->result );
if ( ! $error )
{
// end of recordset
$this->afterLast();
return false;
}
else
{
throw new SQLException( 'Error fetching result'
, $error[ 'code' ] . ': ' . $error[ 'message' ]
);
}
}
// Oracle returns all field names in uppercase and associative indices
// in the result array will be uppercased too.
if ($this->fetchmode === ResultSet::FETCHMODE_ASSOC && $this->lowerAssocCase)
{
$this->fields = array_change_key_case($this->fields, CASE_LOWER);
}
// Advance cursor position
$this->cursorPos++;
return true;
}
/**
* @see ResultSet::getRecordCount()
*/
function getRecordCount()
{
$rows = oci_num_rows( $this->result );
if ( $rows === false )
{
throw new SQLException( 'Error fetching num rows'
, $this->conn->nativeError( $this->result )
);
}
return ( int ) $rows;
}
/**
* @see ResultSet::close()
*/
function close()
{
$this->fields = array();
@oci_free_statement( $this->result );
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* $Id: OCI8Statement.php,v 1.2 2004/03/05 15:46:12 hlellelid Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/Statement.php';
require_once 'creole/common/StatementCommon.php';
/**
* Oracle (OCI8) Statement implementation.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.2 $
* @package creole.drivers.oracle
*/
class OCI8Statement extends StatementCommon implements Statement {
}

View File

@ -0,0 +1,90 @@
<?php
/*
* $Id: OCI8Types.php,v 1.8 2004/03/20 04:16:50 hlellelid Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/CreoleTypes.php';
/**
* Oracle types / type map.
*
* @author David Giffin <david@giffin.org>
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.8 $
* @package creole.drivers.oracle
*/
class OCI8Types extends CreoleTypes {
/** Map Oracle native types to Creole (JDBC) types. */
private static $typeMap = array(
'char' => CreoleTypes::CHAR,
'varchar2' => CreoleTypes::VARCHAR,
'long' => CreoleTypes::LONGVARCHAR,
'number' => CreoleTypes::NUMERIC,
'float' => CreoleTypes::FLOAT,
'integer' => CreoleTypes::INTEGER,
'smallint' => CreoleTypes::SMALLINT,
'double' => CreoleTypes::DOUBLE,
'raw' => CreoleTypes::VARBINARY,
'longraw' => CreoleTypes::LONGVARBINARY,
'date' => CreoleTypes::DATE,
'timestamp' => CreoleTypes::TIMESTAMP,
'blob' => CreoleTypes::BLOB,
'clob' => CreoleTypes::CLOB,
'varray' => CreoleTypes::ARR,
);
/** Reverse mapping, created on demand. */
private static $reverseMap = null;
/**
* This method returns the generic Creole (JDBC-like) type
* when given the native db type.
* @param string $nativeType DB native type (e.g. 'TEXT', 'byetea', etc.).
* @return int Creole native type (e.g. CreoleTypes::LONGVARCHAR, CreoleTypes::BINARY, etc.).
*/
public static function getType($nativeType)
{
$t = str_replace(' ', '', strtolower($nativeType));
if ( substr($t, 0, 9) == 'timestamp' ) return CreoleTypes::TIMESTAMP;
if (isset(self::$typeMap[$t])) {
return self::$typeMap[$t];
} else {
return CreoleTypes::OTHER;
}
}
/**
* This method will return a native type that corresponds to the specified
* Creole (JDBC-like) type.
* If there is more than one matching native type, then the LAST defined
* native type will be returned.
* @param int $creoleType
* @return string Native type string.
*/
public static function getNativeType($creoleType)
{
if (self::$reverseMap === null) {
self::$reverseMap = array_flip(self::$typeMap);
}
return @self::$reverseMap[$creoleType];
}
}

View File

@ -0,0 +1,90 @@
<?php
/*
* $Id: OCI8DatabaseInfo.php,v 1.11 2006/01/17 19:44:40 hlellelid Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/metadata/DatabaseInfo.php';
/**
* Oracle (OCI8) implementation of DatabaseInfo.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.11 $
* @package creole.drivers.oracle.metadata
*/
class OCI8DatabaseInfo extends DatabaseInfo {
private $schema;
public function __construct(Connection $conn) {
parent::__construct($conn);
$dsn = $conn->getDSN();
if (isset($dsn['schema'])) {
$this->schema = $dsn['schema'];
} else {
// For Changing DB/Schema in Meta Data Interface
$this->schema = $dsn['username'];
}
$this->schema = strtoupper( $this->schema );
}
public function getSchema() {
return $this->schema;
}
/**
* @throws SQLException
* @return void
*/
protected function initTables()
{
include_once 'creole/drivers/oracle/metadata/OCI8TableInfo.php';
$sql = "SELECT table_name
FROM all_tables
WHERE owner = '{$this->schema}'";
$statement = @oci_parse($this->conn->getResource(),$sql);
$success = @oci_execute($statement,OCI_DEFAULT);
if (!$success) {
throw new SQLException("Could not get tables", $this->conn->getResource()->nativeError($statement));
}
while ( $statement && $row = oci_fetch_assoc( $statement ) )
{
$row = array_change_key_case($row,CASE_LOWER);
$this->tables[strtoupper($row['table_name'])] = new OCI8TableInfo($this,$row['table_name']);
}
}
/**
* Oracle supports sequences.
*
* @return void
* @throws SQLException
*/
protected function initSequences()
{
// throw new SQLException("MySQL does not support sequences natively.");
}
}

View File

@ -0,0 +1,273 @@
<?php
/*
* $Id: OCI8TableInfo.php,v 1.13 2006/01/06 00:02:38 sethr Exp $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://creole.phpdb.org>.
*/
require_once 'creole/metadata/TableInfo.php';
/**
* Oracle (OCI8) implementation of TableInfo.
*
* @author David Giffin <david@giffin.org>
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision$
* @package creole.drivers.oracle.metadata
*/
class OCI8TableInfo extends TableInfo {
private $schema;
public function __construct(OCI8DatabaseInfo $database, $name)
{
$this->schema = strtoupper( $database->getSchema() );
parent::__construct($database, $name);
$this->name = strtoupper( $this->name );
}
/** Loads the columns for this table. */
protected function initColumns()
{
include_once 'creole/metadata/ColumnInfo.php';
include_once 'creole/drivers/oracle/OCI8Types.php';
// To get all of the attributes we need, we'll actually do
// two separate queries. The first gets names and default values
// the second will fill in some more details.
$sql = "
SELECT column_name
, data_type
, data_precision
, data_length
, data_default
, nullable
, data_scale
FROM all_tab_columns
WHERE table_name = '{$this->name}'
AND OWNER = '{$this->schema}'";
$statement = @oci_parse($this->conn->getResource(),$sql);
$success = @oci_execute($statement,OCI_DEFAULT);
if (!$success) {
throw new SQLException("Could Not Get Columns");
}
while ( $statement && $row = oci_fetch_array( $statement
, OCI_ASSOC + OCI_RETURN_NULLS ) ) {
$row = array_change_key_case($row, CASE_LOWER);
$this->columns[$row['column_name']] = new ColumnInfo( $this
, $row['column_name']
, OCI8Types::getType($row['data_type'])
, $row['data_type']
, $row['data_length']
, $row['data_precision']
, $row['data_scale']
, $row['nullable']
, $row['data_default']
);
}
$this->colsLoaded = true;
}
/** Loads the primary key information for this table. */
protected function initPrimaryKey()
{
include_once 'creole/metadata/PrimaryKeyInfo.php';
// columns have to be loaded first
if (!$this->colsLoaded) $this->initColumns();
// Primary Keys Query
$sql = "SELECT a.owner, a.table_name,
a.constraint_name, a.column_name
FROM all_cons_columns a, all_constraints b
WHERE b.constraint_type = 'P'
AND a.constraint_name = b.constraint_name
AND b.table_name = '{$this->name}'
AND b.owner = '{$this->schema}'
";
$statement = @oci_parse($this->conn->getResource(),$sql);
$success = @oci_execute($statement,OCI_DEFAULT);
if (!$success) {
throw new SQLException("Could Not Get Primary Keys");
}
while ( $statement && $row = oci_fetch_assoc( $statement )) {
$row = array_change_key_case($row,CASE_LOWER);
$name = $row['column_name'];
if (!isset($this->primaryKey)) {
$this->primaryKey = new PrimaryKeyInfo($name);
}
$this->primaryKey->addColumn($this->columns[$name]);
}
$this->pkLoaded = true;
}
/** Loads the indexes for this table. */
protected function initIndexes() {
include_once 'creole/metadata/IndexInfo.php';
// columns have to be loaded first
if (!$this->colsLoaded) $this->initColumns();
// Indexes
$sql = "SELECT
allind.index_name,
allind.table_name,
allind.index_type,
allind.uniqueness,
indcol.column_name
FROM all_indexes allind INNER JOIN all_ind_columns indcol
ON allind.owner = indcol.index_owner
AND allind.index_name = indcol.index_name
WHERE allind.table_owner = '{$this->schema}'
AND allind.table_name = '{$this->name}'
AND allind.index_name NOT IN (SELECT
constraint_name
FROM all_constraints
WHERE constraint_type = 'P')
ORDER BY allind.index_name,
indcol.column_position";
$statement = @oci_parse($this->conn->getResource(),$sql);
$success = @oci_execute($statement,OCI_DEFAULT);
if (!$success) {
throw new SQLException("Could Not Get Primary Keys");
}
// Loop through the returned results, grouping the same key_name together
// adding each column for that key.
while ( $statement && $row = oci_fetch_assoc( $statement )) {
$row = array_change_key_case($row,CASE_LOWER);
$name = $row['index_name'];
$index_col_name = $row['column_name'];
if (!isset($this->indexes[$name])) {
$this->indexes[$name] = new IndexInfo($name);
}
$this->indexes[$name]->addColumn($this->columns[ $index_col_name ]);
}
$this->indexesLoaded = true;
}
/** Load foreign keys */
protected function initForeignKeys() {
include_once 'creole/metadata/ForeignKeyInfo.php';
// columns have to be loaded first
if (!$this->colsLoaded) $this->initColumns();
// Foreign keys
// TODO resolve cross schema references
// use all_cons... to do so, however, very slow queries then
// optimizations are very ugly
$sql = "
SELECT a.owner AS local_owner
, a.table_name AS local_table
, c.column_name AS local_column
, a.constraint_name AS foreign_key_name
, b.owner AS foreign_owner
, b.table_name AS foreign_table
, d.column_name AS foreign_column
, b.constraint_name AS foreign_constraint_name
, a.delete_rule AS on_delete
FROM user_constraints a
, user_constraints b
, user_cons_columns c
, user_cons_columns d
WHERE a.r_constraint_name = b.constraint_name
AND c.constraint_name = a.constraint_name
AND d.constraint_name = b.constraint_name
AND a.r_owner = b.owner
AND a.constraint_type='R'
AND a.table_name = '{$this->name}'
AND a.owner = '{$this->schema}'
";
$statement = @oci_parse($this->conn->getResource(),$sql);
$success = @oci_execute($statement,OCI_DEFAULT);
if (!$success) {
throw new SQLException("Could Not Get Primary Keys");
}
// Loop through the returned results, grouping the same key_name
// together adding each column for that key.
while ( $statement && $row = oci_fetch_assoc( $statement )) {
$row = array_change_key_case($row,CASE_LOWER);
$name = $row['foreign_key_name'];
$foreignTable = $this->database->getTable($row['foreign_table']);
$foreignColumn = $foreignTable->getColumn($row['foreign_column']);
$localTable = $this->database->getTable($row['local_table']);
$localColumn = $localTable->getColumn($row['local_column']);
if (!isset($this->foreignKeys[$name])) {
$this->foreignKeys[$name] = new ForeignKeyInfo($name);
}
switch ( $row[ 'on_delete' ] )
{
case 'CASCADE':
$onDelete = ForeignKeyInfo::CASCADE;
break;
case 'SET NULL':
$onDelete = ForeignKeyInfo::SETNULL;
break;
default:
case 'NO ACTION':
$onDelete = ForeignKeyInfo::NONE;
break;
}
// addReference( local, foreign, onDelete, onUpdate )
// Oracle doesn't support 'on update'
$this->foreignKeys[ $name ]->addReference(
$localColumn
, $foreignColumn
, $onDelete
);
}
$this->fksLoaded = true;
}
}