Заменяем creole на pdo, убрал зависимость от h2o
This commit is contained in:
parent
3c2e614d87
commit
1223d54573
99 changed files with 2 additions and 16962 deletions
|
|
@ -17,13 +17,13 @@ class Controller_Front extends Controller
|
|||
|
||||
public function __construct(Settings $_registry, $_shortcut)
|
||||
{
|
||||
require_once 'creole/Creole.php';
|
||||
require_once 'core/database_pdo.php';
|
||||
parent::__construct();
|
||||
$registry = $_registry;
|
||||
$this->_registry = $_registry;
|
||||
$this->_shortcut = $_shortcut;
|
||||
|
||||
$this->db = Creole::getConnection($registry->readKey(array('system', 'dsn')));
|
||||
$this->db = Database::getConnection($registry->readKey(array('system', 'dsn')));
|
||||
$this->installer = new Installer($_registry);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,135 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: CallableStatement.php,v 1.7 2004/03/20 04:16:49 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/PreparedStatement.php';
|
||||
|
||||
/**
|
||||
* Interface for callable statements.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.7 $
|
||||
* @package creole
|
||||
*/
|
||||
interface CallableStatement extends PreparedStatement {
|
||||
|
||||
/**
|
||||
* Register a parameter as an output param.
|
||||
* @param string $paramIndex The stored procedure param name (e.g. @val1).
|
||||
* @param int $sqlType The type of the parameter (e.g. Type::BIT)
|
||||
* @param int $maxLength The maximum expected length (size) of output parameter.
|
||||
*/
|
||||
public function registerOutParameter($paramIndex, $sqlType, $maxLength = null);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $paramIndex Parameter name (e.g. "@var1").
|
||||
* @return array
|
||||
* @throws SQLException if $paramIndex was not bound as output variable.
|
||||
*/
|
||||
public function getArray($paramIndex);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $paramIndex Parameter name (e.g. "@var1").
|
||||
* @return boolean
|
||||
* @throws SQLException if $paramIndex was not bound as output variable.
|
||||
*/
|
||||
public function getBoolean($paramIndex);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $paramIndex Parameter name (e.g. "@var1").
|
||||
* @return Blob blob object
|
||||
* @throws SQLException if $paramIndex was not bound as output variable.
|
||||
*/
|
||||
public function getBlob($paramIndex);
|
||||
|
||||
/**
|
||||
* @param mixed $paramIndex Column name (string) or index (int).
|
||||
* @return Clob clob object.
|
||||
*/
|
||||
public function getClob($paramIndex);
|
||||
|
||||
/**
|
||||
* Return a formatted date.
|
||||
*
|
||||
* The default format for dates returned is preferred (in your locale, as specified using setlocale())
|
||||
* format w/o time (i.e. strftime("%x", $val)). Override this by specifying a format second parameter. You
|
||||
* can also specify a date()-style formatter; if you do, make sure there are no "%" symbols in your format string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @param string $format Date formatter for use w/ strftime() or date() (it will choose based on examination of format string)
|
||||
* If format is NULL, then the integer unix timestamp will be returned (no formatting performed).
|
||||
* @return mixed Formatted date, or integer unix timestamp (using 00:00:00 for time) if $format was null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getDate($column, $format = '%x');
|
||||
|
||||
/**
|
||||
* @param mixed $paramIndex Column name (string) or index (int).
|
||||
* @return float
|
||||
*/
|
||||
public function getFloat($paramIndex);
|
||||
|
||||
/**
|
||||
* @param mixed $paramIndex Column name (string) or index (int).
|
||||
* @return int
|
||||
*/
|
||||
public function getInt($paramIndex);
|
||||
|
||||
/**
|
||||
* @param mixed $paramIndex Column name (string) or index (int).
|
||||
* @return string
|
||||
*/
|
||||
public function getString($paramIndex);
|
||||
|
||||
/**
|
||||
* Return a formatted time.
|
||||
*
|
||||
* The default format for times returned is preferred (in your locale, as specified using setlocale())
|
||||
* format w/o date (i.e. strftime("%X", $val)). Override this by specifying a format second parameter. You
|
||||
* can also specify a date()-style formatter; if you do, make sure there are no "%" symbols in your format string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @param string $format Date formatter for use w/ strftime() or date() (it will choose based on examination of format string)
|
||||
* If format is NULL, then the integer unix timestamp will be returned (no formatting performed).
|
||||
* @return mixed Formatted time, or integer unix timestamp (using today's date) if $format was null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getTime($column, $format = '%X');
|
||||
|
||||
/**
|
||||
* Return a formatted timestamp.
|
||||
*
|
||||
* The default format for timestamp is ISO standard YYYY-MM-DD HH:MM:SS (i.e. date('Y-m-d H:i:s', $val).
|
||||
* Override this by specifying a format second parameter. You can also specify a strftime()-style formatter.
|
||||
*
|
||||
* Hint: if you want to get the unix timestamp use the "U" formatter string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @param string $format Date formatter for use w/ strftime() or date() (it will choose based on examination of format string)
|
||||
* If format is NULL, then the integer unix timestamp will be returned (no formatting performed).
|
||||
* @return mixed Formatted timestamp, or integer unix timestamp (if $format was null)
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getTimestamp($column, $format = 'Y-m-d H:i:s');
|
||||
|
||||
}
|
||||
|
|
@ -1,220 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: Connection.php,v 1.29 2005/10/17 19:03:50 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>.
|
||||
*/
|
||||
|
||||
include_once 'creole/ResultSet.php'; // we need this for the fetchmode ResultSet flags (constants) that are passed to executeQuery()
|
||||
|
||||
/**
|
||||
* Connection is an abstract base class for DB dialect implementations, and must be
|
||||
* inherited by all such.
|
||||
*
|
||||
* Developer notes:
|
||||
* (1) Make sure that your Connection class can be serialized. See the ConnectionCommon __sleep() and __wakeup() implimentation.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.29 $
|
||||
* @package creole
|
||||
*/
|
||||
interface Connection {
|
||||
|
||||
// Constants that define transaction isolation levels.
|
||||
// [We don't have any code using these yet, so there's no need
|
||||
// to initialize these values at this point.]
|
||||
// const TRANSACTION_NONE = 0;
|
||||
// const TRANSACTION_READ_UNCOMMITTED = 1;
|
||||
// const TRANSACTION_READ_COMMITTED = 2;
|
||||
// const TRANSACTION_REPEATABLE_READ = 3;
|
||||
// const TRANSACTION_SERIALIZABLE = 4;
|
||||
|
||||
/**
|
||||
* Connect to a database and log in as the specified user.
|
||||
*
|
||||
* @param array $dsn The PEAR-style data source hash.
|
||||
* @param int $flags (optional) Flags for connection (e.g. Creole::PERSISTENT). These flags
|
||||
* may apply to any of the driver classes.
|
||||
*/
|
||||
public function connect($dsn, $flags = false);
|
||||
|
||||
/**
|
||||
* Get the PHP native resource for the database connection/link.
|
||||
* @return resource
|
||||
*/
|
||||
public function getResource();
|
||||
|
||||
/**
|
||||
* Get any flags that were passed to connection.
|
||||
* @return int
|
||||
*/
|
||||
public function getFlags();
|
||||
|
||||
/**
|
||||
* Get the DSN array used by connect() method to connect to database.
|
||||
* @see connect()
|
||||
* @return array
|
||||
*/
|
||||
public function getDSN();
|
||||
|
||||
/**
|
||||
* Gets a DatabaseInfo class for the current database.
|
||||
*
|
||||
* This is not modeled on the JDBC MetaData class, but provides a possibly more
|
||||
* useful metadata system. All the same, there may eventually be a getMetaData()
|
||||
* which returns a class that behaves like JDBC's DatabaseMetaData.
|
||||
*
|
||||
* @return DatabaseInfo
|
||||
*/
|
||||
public function getDatabaseInfo();
|
||||
|
||||
/**
|
||||
* Loads and returns an IdGenerator object for current RDBMS.
|
||||
* @return IdGenerator
|
||||
*/
|
||||
public function getIdGenerator();
|
||||
|
||||
/**
|
||||
* Prepares a query for multiple execution with execute().
|
||||
*
|
||||
* With some database backends, this is emulated.
|
||||
* prepare() requires a generic query as string like
|
||||
* "INSERT INTO numbers VALUES(?,?,?)". The ? are placeholders.
|
||||
*
|
||||
* IMPORTANT: All occurrences of the placeholder (?) will be assumed
|
||||
* to be a parameter. Therefore be sure not to have ? anywhere else in
|
||||
* the query.
|
||||
*
|
||||
* So, ... DO NOT MIX WILDCARDS WITH ALREADY-PREPARED QUERIES
|
||||
*
|
||||
* INCORRECT:
|
||||
* SELECT * FROM mytable WHERE id = ? AND title = 'Where are you?' and body LIKE ?
|
||||
*
|
||||
* CORRECT:
|
||||
* SELECT * FROM mytable WHERE id = ? AND title = ? and body LIKE ?
|
||||
*
|
||||
* @param string $sql The query to prepare.
|
||||
* @return PreparedStatement
|
||||
* @throws SQLException
|
||||
* @see PreparedStatement::execute()
|
||||
*/
|
||||
public function prepareStatement($sql);
|
||||
|
||||
/**
|
||||
* Creates a new empty Statement.
|
||||
* @return Statement
|
||||
*/
|
||||
public function createStatement();
|
||||
|
||||
/**
|
||||
* If RDBMS supports native LIMIT/OFFSET then query SQL is modified
|
||||
* so that no emulation is performed in ResultSet.
|
||||
*
|
||||
* @param string &$sql The query that will be modified.
|
||||
* @param int $offset
|
||||
* @param int $limit
|
||||
* @return void
|
||||
* @throws SQLException - if unable to modify query for any reason.
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit);
|
||||
|
||||
/**
|
||||
* Executes the SQL query in this PreparedStatement object and returns the resultset.
|
||||
*
|
||||
* @param string $sql The SQL statement.
|
||||
* @param int $fetchmode
|
||||
* @return object ResultSet
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null);
|
||||
|
||||
/**
|
||||
* Executes the SQL INSERT, UPDATE, or DELETE statement.
|
||||
*
|
||||
* @param string $sql This method may optionally be called with the SQL statement.
|
||||
* @return int Number of affected rows (or 0 for drivers that return nothing).
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public function executeUpdate($sql);
|
||||
|
||||
/**
|
||||
* Creates a CallableStatement object for calling database stored procedures.
|
||||
*
|
||||
* @param string $sql
|
||||
* @return CallableStatement
|
||||
*/
|
||||
public function prepareCall($sql);
|
||||
|
||||
/**
|
||||
* Free the db resources.
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
|
||||
/**
|
||||
* Returns false if connection is closed.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isConnected();
|
||||
|
||||
/**
|
||||
* Get auto-commit status.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getAutoCommit();
|
||||
|
||||
/**
|
||||
* Enable/disable automatic commits.
|
||||
*
|
||||
* Pushes SQLWarning onto $warnings stack if the autocommit value is being changed mid-transaction. This function
|
||||
* is overridden by driver classes so that they can perform the necessary begin/end transaction SQL.
|
||||
*
|
||||
* If auto-commit is being set to TRUE, then the current transaction will be committed immediately.
|
||||
*
|
||||
* @param boolean $bit New value for auto commit.
|
||||
* @return void
|
||||
*/
|
||||
public function setAutoCommit($bit);
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
*
|
||||
*/
|
||||
public function begin();
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
*
|
||||
*/
|
||||
public function commit();
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
*
|
||||
*/
|
||||
public function rollback();
|
||||
|
||||
/**
|
||||
* Gets the number of rows affected by the data manipulation
|
||||
* query.
|
||||
*
|
||||
* @return int Number of rows affected by the last query.
|
||||
*/
|
||||
public function getUpdateCount();
|
||||
|
||||
}
|
||||
|
|
@ -1,390 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: Creole.php,v 1.14 2006/01/17 20:06:31 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>.
|
||||
*/
|
||||
|
||||
include_once 'creole/SQLException.php';
|
||||
include_once 'creole/Connection.php';
|
||||
|
||||
// static:
|
||||
// track errors is used by drivers to get better error messages
|
||||
// make sure it's set.
|
||||
|
||||
@ini_set('track_errors', true);
|
||||
|
||||
/**
|
||||
* This is the class that manages the database drivers.
|
||||
*
|
||||
* There are a number of default drivers (at the time of writing this comment: MySQL, MSSQL, SQLite, PgSQL, Oracle)
|
||||
* that are "shipped" with Creole. You may wish to either add a new driver or swap out one of the existing drivers
|
||||
* for your own custom driver. To do this you simply need to register your driver using the registerDriver() method.
|
||||
*
|
||||
* Note that you register your Connection class because the Connection class is responsible for calling the other
|
||||
* driver classes (e.g. ResultSet, PreparedStatement, etc.).
|
||||
*
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.14 $
|
||||
* @package creole
|
||||
*/
|
||||
class Creole {
|
||||
|
||||
/**
|
||||
* Constant that indicates a connection object should be used.
|
||||
*/
|
||||
const PERSISTENT = 1;
|
||||
|
||||
/**
|
||||
* Flag to pass to the connection to indicate that no case conversions
|
||||
* should be performed by ResultSet on keys of fetched rows.
|
||||
* @deprecated use COMPAT_ASSOC_LOWER
|
||||
*/
|
||||
const NO_ASSOC_LOWER = 16;
|
||||
|
||||
/**
|
||||
* Flag to pass to the connection to indicate that a to-lower case conversion
|
||||
* should be performed by ResultSet on keys of fetched rows.
|
||||
*/
|
||||
const COMPAT_ASSOC_LOWER = 32;
|
||||
|
||||
/**
|
||||
* Flag to pass to the connection to indicate that an rtrim() should be performed
|
||||
* on strings (using ResultSet->getString(), etc.).
|
||||
*/
|
||||
const COMPAT_RTRIM_STRING = 64;
|
||||
|
||||
/**
|
||||
* Flag to indicate that all compatibility flags should be set.
|
||||
*/
|
||||
const COMPAT_ALL = 96;
|
||||
|
||||
/**
|
||||
* Map of built-in drivers.
|
||||
* Change or add your own using registerDriver()
|
||||
* @see registerDriver()
|
||||
* @var array Hash mapping phptype => driver class (in dot-path notation, e.g. 'mysql' => 'creole.drivers.mysql.MySQLConnection').
|
||||
*/
|
||||
private static $driverMap = array( 'mysql' => 'creole.drivers.mysql.MySQLConnection',
|
||||
'mysqli' => 'creole.drivers.mysqli.MySQLiConnection',
|
||||
'pgsql' => 'creole.drivers.pgsql.PgSQLConnection',
|
||||
'sqlite' => 'creole.drivers.sqlite.SQLiteConnection',
|
||||
'oracle' => 'creole.drivers.oracle.OCI8Connection',
|
||||
'mssql' => 'creole.drivers.mssql.MSSQLConnection',
|
||||
'odbc' => 'creole.drivers.odbc.ODBCConnection'
|
||||
);
|
||||
|
||||
/**
|
||||
* Map of already established connections
|
||||
* @see getConnection()
|
||||
* @var array Hash mapping connection DSN => Connection instance
|
||||
*/
|
||||
private static $connectionMap = array();
|
||||
|
||||
/**
|
||||
* Register your own RDBMS driver class.
|
||||
*
|
||||
* You can use this to specify your own class that replaces a default driver or
|
||||
* adds support for a new driver. Register your own class by specifying the
|
||||
* 'phptype' (e.g. mysql) and a dot-path notation to where your Connection class is
|
||||
* relative to any location on the include path. You can also specify '*' as the phptype
|
||||
* if you want to register a driver that will handle any native type (e.g. if creating
|
||||
* a set of decorator classes that log SQL before calling native driver methods). YOU CAN
|
||||
* ONLY REGISTER ONE CATCHALL ('*') DRIVER.
|
||||
* <p>
|
||||
* Note: the class you need to register is your Connection class because this is the
|
||||
* class that's responsible for instantiating the other classes that are part of your
|
||||
* driver. It is possible to mix & match drivers -- i.e. to write a custom driver where
|
||||
* the Connection object just instantiates stock classes for ResultSet and PreparedStatement.
|
||||
* Note that if you wanted to "override" only the ResultSet class you would also have to override
|
||||
* the Connection and PreparedStatement classes so that they would return the correct ResultSet
|
||||
* class. In the future we may implement a more "packaged" approach to drivers; for now we
|
||||
* want to keep it simple.
|
||||
*
|
||||
* @param string $phptype The phptype (mysql, mssql, etc.). This is first part of DSN URL (e.g. mysql://localhost/...).
|
||||
* You may also specify '*' to register a driver that will "wrap" the any native drivers.
|
||||
* @param string $dotpath A dot-path locating your class. For example 'creole.drivers.mssql.MSSQLConnection'
|
||||
* will be included like: include 'creole/drivers/mssql/MSSQLConnection.php' and the
|
||||
* classname will be assumed to be 'MSSQLConnection'.
|
||||
* @return void
|
||||
*/
|
||||
public static function registerDriver($phptype, $dotpath)
|
||||
{
|
||||
self::$driverMap[$phptype] = $dotpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the driver for a PHP type. Note that this will remove user-registered
|
||||
* drivers _and_ the default drivers.
|
||||
* @param string $phptype The PHP type for driver to de-register.
|
||||
* @see registerDriver()
|
||||
*/
|
||||
public static function deregisterDriver($phptype)
|
||||
{
|
||||
unset(self::$driverMap[$phptype]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class path to the driver registered for specified type.
|
||||
* @param string $phptype The phptype handled by driver (e.g. 'mysql', 'mssql', '*').
|
||||
* @return string The driver class in dot-path notation (e.g. creole.drivers.mssql.MSSQLConnection)
|
||||
* or NULL if no registered driver found.
|
||||
*/
|
||||
public static function getDriver($phptype)
|
||||
{
|
||||
if (isset(self::$driverMap[$phptype])) {
|
||||
return self::$driverMap[$phptype];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DB connection object and connect to the specified
|
||||
* database
|
||||
*
|
||||
* @param mixed $dsn "data source name", see the self::parseDSN
|
||||
* method for a description of the dsn format. Can also be
|
||||
* specified as an array of the format returned by DB::parseDSN().
|
||||
|
||||
* @param int $flags Connection flags (e.g. PERSISTENT).
|
||||
*
|
||||
* @return Connection Newly created DB connection object
|
||||
* @throws SQLException
|
||||
* @see self::parseDSN()
|
||||
*/
|
||||
public static function getConnection($dsn, $flags = 0)
|
||||
{
|
||||
if (is_array($dsn)) {
|
||||
$dsninfo = $dsn;
|
||||
} else {
|
||||
$dsninfo = self::parseDSN($dsn);
|
||||
}
|
||||
|
||||
// gather any flags from the DSN
|
||||
if ( isset ( $dsninfo['persistent'] ) && ! empty ( $dsninfo['persistent'] ) )
|
||||
$flags |= Creole::PERSISTENT;
|
||||
if ( isset ( $dsninfo['compat_assoc_lower'] ) && ! empty ( $dsninfo['compat_assoc_lower'] ) )
|
||||
$flags |= Creole::COMPAT_ASSOC_LOWER;
|
||||
if ( isset ( $dsninfo['compat_rtrim_string'] ) && ! empty ( $dsninfo['compat_rtrim_string'] ) )
|
||||
$flags |= Creole::COMPAT_RTRIM_STRING;
|
||||
if ( isset ( $dsninfo['compat_all'] ) && ! empty ( $dsninfo['compat_all'] ) )
|
||||
$flags |= Creole::COMPAT_ALL;
|
||||
|
||||
if ($flags & Creole::NO_ASSOC_LOWER) {
|
||||
trigger_error("The Creole::NO_ASSOC_LOWER flag has been deprecated, and is now the default behavior. Use Creole::COMPAT_ASSOC_LOWER to lowercase resulset keys.", E_USER_WARNING);
|
||||
}
|
||||
|
||||
// sort $dsninfo by keys so the serialized result is always the same
|
||||
// for identical connection parameters, no matter what their order is
|
||||
ksort($dsninfo);
|
||||
$connectionMapKey = crc32(serialize($dsninfo + array('compat_flags' => ($flags & Creole::COMPAT_ALL))));
|
||||
|
||||
// see if we already have a connection with these parameters cached
|
||||
if(isset(self::$connectionMap[$connectionMapKey]))
|
||||
{
|
||||
// persistent connections will be used if a non-persistent one was requested and is available
|
||||
// but a persistent connection will be created if a non-persistent one is present
|
||||
|
||||
// TODO: impliment auto close of non persistent and replacing the
|
||||
// non persistent with the persistent object so as we dont have
|
||||
// both links open for no reason
|
||||
|
||||
if( isset(self::$connectionMap[$connectionMapKey][1]) ) { // is persistent
|
||||
// a persistent connection with these parameters is already there,
|
||||
// so we return it, no matter what was specified as persistent flag
|
||||
$con = self::$connectionMap[$connectionMapKey][1];
|
||||
} else {
|
||||
// we don't have a persistent connection, and since the persistent
|
||||
// flag wasn't set either, we just return the non-persistent connection
|
||||
$con = self::$connectionMap[$connectionMapKey][0];
|
||||
}
|
||||
|
||||
// if we're here, a non-persistent connection was already there, but
|
||||
// the user wants a persistent one, so it will be created
|
||||
|
||||
if ($con->isConnected())
|
||||
return $con;
|
||||
}
|
||||
|
||||
// support "catchall" drivers which will themselves handle the details of connecting
|
||||
// using the proper RDBMS driver.
|
||||
if (isset(self::$driverMap['*'])) {
|
||||
$type = '*';
|
||||
} else {
|
||||
$type = $dsninfo['phptype'];
|
||||
if (!isset(self::$driverMap[$type])) {
|
||||
throw new SQLException("No driver has been registered to handle connection type: $type");
|
||||
}
|
||||
}
|
||||
|
||||
// may need to make this more complex if we add support
|
||||
// for 'dbsyntax'
|
||||
$clazz = self::import(self::$driverMap[$type]);
|
||||
$obj = new $clazz();
|
||||
|
||||
if (!($obj instanceof Connection)) {
|
||||
throw new SQLException("Class does not implement creole.Connection interface: $clazz");
|
||||
}
|
||||
|
||||
try {
|
||||
$obj->connect($dsninfo, $flags);
|
||||
} catch(SQLException $sqle) {
|
||||
$sqle->setUserInfo($dsninfo);
|
||||
throw $sqle;
|
||||
}
|
||||
$persistent = ($flags & Creole::PERSISTENT) === Creole::PERSISTENT;
|
||||
return self::$connectionMap[$connectionMapKey][(int)$persistent] = $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a data source name.
|
||||
*
|
||||
* This isn't quite as powerful as DB::parseDSN(); it's also a lot simpler, a lot faster,
|
||||
* and many fewer lines of code.
|
||||
*
|
||||
* A array with the following keys will be returned:
|
||||
* phptype: Database backend used in PHP (mysql, odbc etc.)
|
||||
* protocol: Communication protocol to use (tcp, unix etc.)
|
||||
* hostspec: Host specification (hostname[:port])
|
||||
* database: Database to use on the DBMS server
|
||||
* username: User name for login
|
||||
* password: Password for login
|
||||
*
|
||||
* The format of the supplied DSN is in its fullest form:
|
||||
*
|
||||
* phptype://username:password@hostspec/database
|
||||
*
|
||||
* Most variations are allowed:
|
||||
*
|
||||
* phptype://username:password@protocol(hostspec:110)//usr/db_file.db
|
||||
* phptype://username:password@hostspec/database_name
|
||||
* phptype://username:password@hostspec
|
||||
* phptype://username@hostspec
|
||||
* phptype://hostspec/database
|
||||
* phptype://hostspec
|
||||
* phptype
|
||||
*
|
||||
* @param string $dsn Data Source Name to be parsed
|
||||
* @return array An associative array
|
||||
*/
|
||||
public static function parseDSN($dsn)
|
||||
{
|
||||
if (is_array($dsn)) {
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
$parsed = array(
|
||||
'phptype' => null,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
'protocol' => null,
|
||||
'hostspec' => null,
|
||||
'port' => null,
|
||||
'socket' => null,
|
||||
'database' => null
|
||||
);
|
||||
|
||||
$preg_query = "!^(([a-z0-9]+)(\(([^()]+)\))?)(://((((([^@/:]+)(:([^@/]+))?)@)?((([a-z]+)\((([^?():]+)(:([^()?]+))?)\))|((([^/?:]+)(:([^/?]+))?))))/?)?([^?]+)?(\?(.+))?)?$!i";
|
||||
|
||||
$info = array();
|
||||
|
||||
if (preg_match($preg_query,$dsn,$info)) { // only if it is matching
|
||||
|
||||
$parsed['phptype'] = @$info[2]; // Group 2 should always exist.
|
||||
|
||||
// Don't know what to do with Group 4: phptype(xx) should => check first if available
|
||||
|
||||
if (isset($info[5])) { // There is more than just the phptype
|
||||
|
||||
if (strlen($info[10]) > 0) { // There is a username specified
|
||||
$parsed['username'] = @$info[10];
|
||||
}
|
||||
|
||||
if (strlen($info[12]) > 0) { // There is a password specified
|
||||
$parsed['password'] = @$info[12];
|
||||
}
|
||||
|
||||
if (strlen($info[15]) > 0) { // There is a protocol specified: protocol(hostspec)
|
||||
$parsed['protocol'] = @$info[15];
|
||||
|
||||
if ($parsed["protocol"] === "unix") {
|
||||
$parsed['socket'] = @$info[16];
|
||||
} else {
|
||||
$parsed["hostspec"] = @$info[17];
|
||||
if (strlen($info[19]) > 0) {
|
||||
$parsed["port"] = @$info[19];
|
||||
}
|
||||
}
|
||||
} elseif (strlen($info[20]) > 0) {
|
||||
$parsed["hostspec"] = @$info[22];
|
||||
|
||||
if ((isset($info[24]) && (strlen($info[24]) > 0))) { // There is a port set (not always available)
|
||||
$parsed["port"] = @$info[24];
|
||||
}
|
||||
}
|
||||
|
||||
if ((isset($info[25])) && (strlen($info[25]) > 0)) { // There is a database
|
||||
$parsed["database"] = @$info[25];
|
||||
}
|
||||
|
||||
if ((isset($info[27])) && (strlen($info[27]) >0)) { // There is a query
|
||||
$opts = explode('&', $info[27]);
|
||||
foreach ($opts as $opt) {
|
||||
list($key, $value) = explode('=', $opt);
|
||||
if (!isset($parsed[$key])) { // don't allow params overwrite
|
||||
$parsed[$key] = urldecode($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include once a file specified in DOT notation.
|
||||
* Package notation is expected to be relative to a location
|
||||
* on the PHP include_path.
|
||||
* @param string $class
|
||||
* @return string unqualified classname
|
||||
* @throws SQLException - if class does not exist and cannot load file
|
||||
* - if after loading file class still does not exist
|
||||
*/
|
||||
public static function import($class) {
|
||||
if (!class_exists($class, false)) {
|
||||
$path = strtr($class, '.', DIRECTORY_SEPARATOR) . '.php';
|
||||
$ret = include_once($path);
|
||||
if ($ret === false) {
|
||||
throw new SQLException("Unable to load driver class: " . $class);
|
||||
}
|
||||
// get just classname ('path.to.ClassName' -> 'ClassName')
|
||||
$pos = strrpos($class, '.');
|
||||
if ($pos !== false) {
|
||||
$class = substr($class, $pos + 1);
|
||||
}
|
||||
if (!class_exists($class)) {
|
||||
throw new SQLException("Unable to find loaded class: $class (Hint: make sure classname matches filename)");
|
||||
}
|
||||
}
|
||||
return $class;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: CreoleTypes.php,v 1.18 2005/11/07 22:38:52 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic Creole types modeled on JDBC types.
|
||||
*
|
||||
* @author David Giffin <david@giffin.org>
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.18 $
|
||||
* @package creole
|
||||
*/
|
||||
abstract class CreoleTypes {
|
||||
|
||||
const BOOLEAN = 1;
|
||||
const BIGINT = 2;
|
||||
const SMALLINT = 3;
|
||||
const TINYINT = 4;
|
||||
const INTEGER = 5;
|
||||
const CHAR = 6;
|
||||
const VARCHAR = 7;
|
||||
const TEXT = 17;
|
||||
const FLOAT = 8;
|
||||
const DOUBLE = 9;
|
||||
const DATE = 10;
|
||||
const TIME = 11;
|
||||
const TIMESTAMP = 12;
|
||||
const VARBINARY = 13;
|
||||
const NUMERIC = 14;
|
||||
const BLOB = 15;
|
||||
const CLOB = 16;
|
||||
const LONGVARCHAR = 17;
|
||||
const DECIMAL = 18;
|
||||
const REAL = 19;
|
||||
const BINARY = 20;
|
||||
const LONGVARBINARY = 21;
|
||||
const YEAR = 22;
|
||||
|
||||
/** this is "ARRAY" from JDBC types */
|
||||
const ARR = 23;
|
||||
|
||||
const OTHER = -1;
|
||||
|
||||
/** Map of Creole type integers to the setter/getter affix. */
|
||||
protected static $affixMap = array(
|
||||
self::BOOLEAN => 'Boolean',
|
||||
self::BIGINT => 'String',
|
||||
self::CHAR => 'String',
|
||||
self::DATE => 'Date',
|
||||
self::DOUBLE => 'Float',
|
||||
self::FLOAT => 'Float',
|
||||
self::INTEGER => 'Int',
|
||||
self::SMALLINT => 'Int',
|
||||
self::TINYINT => 'Int',
|
||||
self::TIME => 'Time',
|
||||
self::TIMESTAMP => 'Timestamp',
|
||||
self::VARCHAR => 'String',
|
||||
self::VARBINARY => 'Blob',
|
||||
self::NUMERIC => 'Float',
|
||||
self::BLOB => 'Blob',
|
||||
self::CLOB => 'Clob',
|
||||
self::LONGVARCHAR => 'String',
|
||||
self::DECIMAL => 'Float',
|
||||
self::REAL => 'Float',
|
||||
self::BINARY => 'Blob',
|
||||
self::LONGVARBINARY => 'Blob',
|
||||
self::YEAR => 'Int',
|
||||
self::ARR => 'Array',
|
||||
self::OTHER => '', // get() and set() for unknown
|
||||
);
|
||||
|
||||
/** Map of Creole type integers to their textual name. */
|
||||
protected static $creoleTypeMap = array(
|
||||
self::BOOLEAN => 'BOOLEAN',
|
||||
self::BIGINT => 'BIGINT',
|
||||
self::SMALLINT => 'SMALLINT',
|
||||
self::TINYINT => 'TINYINT',
|
||||
self::INTEGER => 'INTEGER',
|
||||
self::NUMERIC => 'NUMERIC',
|
||||
self::DECIMAL => 'DECIMAL',
|
||||
self::REAL => 'REAL',
|
||||
self::FLOAT => 'FLOAT',
|
||||
self::DOUBLE => 'DOUBLE',
|
||||
self::CHAR => 'CHAR',
|
||||
self::VARCHAR => 'VARCHAR',
|
||||
self::TEXT => 'TEXT',
|
||||
self::TIME => 'TIME',
|
||||
self::TIMESTAMP => 'TIMESTAMP',
|
||||
self::DATE => 'DATE',
|
||||
self::YEAR => 'YEAR',
|
||||
self::VARBINARY => 'VARBINARY',
|
||||
self::BLOB => 'BLOB',
|
||||
self::CLOB => 'CLOB',
|
||||
self::LONGVARCHAR => 'LONGVARCHAR',
|
||||
self::BINARY => 'BINARY',
|
||||
self::LONGVARBINARY => 'LONGVARBINARY',
|
||||
self::ARR => 'ARR',
|
||||
self::OTHER => 'OTHER', // string is "raw" return
|
||||
);
|
||||
|
||||
/**
|
||||
* 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. Types::LONGVARCHAR, Types::BINARY, etc.).
|
||||
*/
|
||||
abstract static function getType($nativeType);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return string Native type string.
|
||||
*/
|
||||
abstract static function getNativeType($creoleType);
|
||||
|
||||
/**
|
||||
* Gets the "affix" to use for ResultSet::get*() and PreparedStatement::set*() methods.
|
||||
* <code>
|
||||
* $setter = 'set' . CreoleTypes::getAffix(CreoleTypes::INTEGER);
|
||||
* $stmt->$setter(1, $intval);
|
||||
* // or
|
||||
* $getter = 'get' . CreoleTypes::getAffix(CreoleTypes::TIMESTAMP);
|
||||
* $timestamp = $rs->$getter();
|
||||
* </code>
|
||||
* @param int $creoleType The Creole types.
|
||||
* @return string The default affix for getting/setting cols of this type.
|
||||
* @throws SQLException if $creoleType does not correspond to an affix
|
||||
*/
|
||||
public static function getAffix($creoleType)
|
||||
{
|
||||
if (!isset(self::$affixMap[$creoleType])) {
|
||||
$e = new SQLException("Unable to return 'affix' for unknown CreoleType: " . $creoleType);
|
||||
throw $e;
|
||||
}
|
||||
return self::$affixMap[$creoleType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the integer type, this method will return the corresponding type name.
|
||||
* @param int $creoleType the integer Creole type.
|
||||
* @return string The name of the Creole type (e.g. 'VARCHAR').
|
||||
*/
|
||||
public static function getCreoleName($creoleType)
|
||||
{
|
||||
if (!isset(self::$creoleTypeMap[$creoleType])) {
|
||||
return null;
|
||||
}
|
||||
return self::$creoleTypeMap[$creoleType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the name of a type (e.g. 'VARCHAR') this method will return the corresponding integer.
|
||||
* @param string $creoleTypeName The case-sensisive (must be uppercase) name of the Creole type (e.g. 'VARCHAR').
|
||||
* @return int the Creole type.
|
||||
*/
|
||||
public static function getCreoleCode($creoleTypeName)
|
||||
{
|
||||
$type = array_search($creoleTypeName, self::$creoleTypeMap);
|
||||
if ($type === false) {
|
||||
return null;
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Interface for classes that provide functionality to get SEQUENCE or AUTO-INCREMENT ids from the database.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole
|
||||
*/
|
||||
interface IdGenerator {
|
||||
|
||||
/** SEQUENCE id generator type */
|
||||
const SEQUENCE = 1;
|
||||
|
||||
/** AUTO INCREMENT id generator type */
|
||||
const AUTOINCREMENT = 2;
|
||||
|
||||
/**
|
||||
* Convenience method that returns TRUE if id is generated
|
||||
* before an INSERT statement. This is the same as checking
|
||||
* whether the generator type is SEQUENCE.
|
||||
* @return boolean TRUE if gen id method is SEQUENCE
|
||||
* @see getIdMethod()
|
||||
*/
|
||||
public function isBeforeInsert();
|
||||
|
||||
/**
|
||||
* Convenience method that returns TRUE if id is generated
|
||||
* after an INSERT statement. This is the same as checking
|
||||
* whether the generator type is AUTOINCREMENT.
|
||||
* @return boolean TRUE if gen id method is AUTOINCREMENT
|
||||
* @see getIdMethod()
|
||||
*/
|
||||
public function isAfterInsert();
|
||||
|
||||
/**
|
||||
* Get the preferred type / style for generating ids for RDBMS.
|
||||
* @return int SEQUENCE or AUTOINCREMENT
|
||||
*/
|
||||
public function getIdMethod();
|
||||
|
||||
/**
|
||||
* Get the autoincrement or sequence id given the current connection
|
||||
* and any additional needed info (e.g. sequence name for sequences).
|
||||
* <p>
|
||||
* Note: if you take advantage of the fact that $keyInfo may not be specified
|
||||
* you should make sure that your code is setup in such a way that it will
|
||||
* be portable if you change from an RDBMS that uses AUTOINCREMENT to one that
|
||||
* uses SEQUENCE (i.e. in which case you would need to specify sequence name).
|
||||
*
|
||||
* @param mixed $keyInfo Any additional information (e.g. sequence name) needed to fetch the id.
|
||||
* @return int The last id / next id.
|
||||
*/
|
||||
public function getId($keyInfo = null);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PreparedStatement.php,v 1.21 2005/03/29 16:56:09 gamr 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for a pre-compiled SQL statement.
|
||||
*
|
||||
* Many drivers do not take advantage of pre-compiling SQL statements; for these
|
||||
* cases the precompilation is emulated. This emulation comes with slight penalty involved
|
||||
* in parsing the queries, but provides other benefits such as a cleaner object model and ability
|
||||
* to work with BLOB and CLOB values w/o needing special LOB-specific routines.
|
||||
*
|
||||
* This class is abstract because there are driver-specific implementations in [clearly] how queries
|
||||
* are executed, and how parameters are bound.
|
||||
*
|
||||
* This class is not as abstract as the JDBC version. For exmple, if you are using a driver
|
||||
* that uses name-based query param substitution, then you'd better bind your variables to
|
||||
* names rather than index numbers. e.g. in Oracle
|
||||
* <code>
|
||||
* $stmt = $conn->prepareStatement("INSERT INTO users (name, passwd) VALUES (:name, :pass)");
|
||||
* $stmt->setString(":name", $name);
|
||||
* $stmt->executeUpdate();
|
||||
* </code>
|
||||
*
|
||||
* Developer note: In many ways this interface is an extension of the Statement interface. However, due
|
||||
* to limitations in PHP5's interface extension model (specifically that you cannot change signatures on
|
||||
* methods defined in parent interface), we cannot extend the Statement interface.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.21 $
|
||||
* @package creole
|
||||
*/
|
||||
interface PreparedStatement {
|
||||
|
||||
/**
|
||||
* Gets the db Connection that created this statement.
|
||||
* @return Connection
|
||||
*/
|
||||
public function getConnection();
|
||||
|
||||
/**
|
||||
* Get the PHP native resource for the statement (if supported).
|
||||
* @return resource
|
||||
*/
|
||||
public function getResource();
|
||||
|
||||
/**
|
||||
* Free resources associated with this statement.
|
||||
* Some drivers will need to implement this method to free
|
||||
* database result resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
|
||||
/**
|
||||
* Get result set.
|
||||
* This assumes that the last thing done was an executeQuery() or an execute()
|
||||
* with SELECT-type query.
|
||||
*
|
||||
* @return RestultSet Last ResultSet or <code>null</code> if not applicable.
|
||||
*/
|
||||
public function getResultSet();
|
||||
|
||||
/**
|
||||
* Gets next result set (if this behavior is supported by driver).
|
||||
* Some drivers (e.g. MSSQL) support returning multiple result sets -- e.g.
|
||||
* from stored procedures.
|
||||
*
|
||||
* This function also closes any current restult set.
|
||||
*
|
||||
* Default behavior is for this function to return false. Driver-specific
|
||||
* implementations of this class can override this method if they actually
|
||||
* support multiple result sets.
|
||||
*
|
||||
* @return boolean True if there is another result set, otherwise false.
|
||||
*/
|
||||
public function getMoreResults();
|
||||
|
||||
/**
|
||||
* Get update count.
|
||||
*
|
||||
* @return int Number of records affected, or <code>null</code> if not applicable.
|
||||
*/
|
||||
public function getUpdateCount();
|
||||
|
||||
/**
|
||||
* Sets the maximum number of rows to return from db.
|
||||
* This will affect the SQL if the RDBMS supports native LIMIT; if not,
|
||||
* it will be emulated. Limit only applies to queries (not update sql).
|
||||
* @param int $v Maximum number of rows or 0 for all rows.
|
||||
* @return void
|
||||
*/
|
||||
public function setLimit($v);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of rows to return or 0 for all.
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit();
|
||||
|
||||
/**
|
||||
* Sets the start row.
|
||||
* This will affect the SQL if the RDBMS supports native OFFSET; if not,
|
||||
* it will be emulated. Offset only applies to queries (not update) and
|
||||
* only is evaluated when LIMIT is set!
|
||||
* @param int $v
|
||||
* @return void
|
||||
*/
|
||||
public function setOffset($v);
|
||||
|
||||
/**
|
||||
* Returns the start row.
|
||||
* Offset only applies when Limit is set!
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset();
|
||||
|
||||
/**
|
||||
* Executes the SQL query in this PreparedStatement object and returns the resultset generated by the query.
|
||||
* We support two signatures for this method:
|
||||
* - $stmt->executeQuery(ResultSet::FETCHMODE_NUM);
|
||||
* - $stmt->executeQuery(array($param1, $param2), ResultSet::FETCHMODE_NUM);
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* A generic set method.
|
||||
*
|
||||
* You can use this if you don't want to concern yourself with the details. It involves
|
||||
* slightly more overhead than the specific settesr, since it grabs the PHP type to determine
|
||||
* which method makes most sense.
|
||||
*
|
||||
* @param int $paramIndex
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
public function set($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* Sets an array.
|
||||
* Unless a driver-specific method is used, this means simply serializing
|
||||
* the passed parameter and storing it as a string.
|
||||
* @param int $paramIndex
|
||||
* @param array $value
|
||||
* @return void
|
||||
*/
|
||||
public function setArray($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* Sets a boolean value.
|
||||
* Default behavior is true = 1, false = 0.
|
||||
* @param int $paramIndex
|
||||
* @param boolean $value
|
||||
* @return void
|
||||
*/
|
||||
public function setBoolean($paramIndex, $value);
|
||||
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param mixed $blob Blob object or string containing data.
|
||||
* @return void
|
||||
*/
|
||||
public function setBlob($paramIndex, $blob);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param mixed $clob Clob object or string containing data.
|
||||
* @return void
|
||||
*/
|
||||
public function setClob($paramIndex, $clob);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setDate($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param float $value
|
||||
* @return void
|
||||
*/
|
||||
public function setFloat($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param int $value
|
||||
* @return void
|
||||
*/
|
||||
public function setInt($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @return void
|
||||
*/
|
||||
public function setNull($paramIndex);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setString($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setTime($paramIndex, $value);
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setTimestamp($paramIndex, $value);
|
||||
|
||||
}
|
||||
|
|
@ -1,380 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ResultSet.php,v 1.28 2006/01/17 19:44:38 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the interface for classes the wrap db results.
|
||||
*
|
||||
* The get*() methods in this interface will format values before returning them. Note
|
||||
* that if they will return null if the database returned NULL. If the requested column does
|
||||
* not exist than an exception (SQLException) will be thrown.
|
||||
*
|
||||
* <code>
|
||||
* $rs = $conn->executeQuery("SELECT MAX(stamp) FROM event", ResultSet::FETCHMODE_NUM);
|
||||
* $rs->next();
|
||||
*
|
||||
* $max_stamp = $rs->getTimestamp(1, "d/m/Y H:i:s");
|
||||
* // $max_stamp will be date string or null if no MAX(stamp) was found
|
||||
*
|
||||
* $max_stamp = $rs->getTimestamp("max(stamp)", "d/m/Y H:i:s");
|
||||
* // will THROW EXCEPTION, because the resultset was fetched using numeric indexing
|
||||
* // SQLException: Invalid resultset column: max(stamp)
|
||||
* </code>
|
||||
*
|
||||
* This class implements SPL IteratorAggregate, so you may iterate over the database results
|
||||
* using foreach():
|
||||
* <code>
|
||||
* foreach($rs as $row) {
|
||||
* print_r($row); // row is assoc array returned by getRow()
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.28 $
|
||||
* @package creole
|
||||
*/
|
||||
interface ResultSet extends IteratorAggregate {
|
||||
|
||||
/**
|
||||
* Index result set by field name.
|
||||
*/
|
||||
const FETCHMODE_ASSOC = 1;
|
||||
|
||||
/**
|
||||
* Index result set numerically.
|
||||
*/
|
||||
const FETCHMODE_NUM = 2;
|
||||
|
||||
/**
|
||||
* Get the PHP native resource for the result.
|
||||
* Arguably this should not be part of the interface: i.e. every driver should implement
|
||||
* it if they have a result resource, but conceivably drivers could be created that do
|
||||
* not. For now every single driver does have a "dblink" resource property, and other
|
||||
* classes (e.g. ResultSet) need this info in order to get correct native errors. We'll
|
||||
* leave it in for now, as it helps with driver development, with the caveat that it
|
||||
* could be removed from the interface at a later point.
|
||||
* @return resource Query result or NULL if not not applicable.
|
||||
*/
|
||||
public function getResource();
|
||||
|
||||
/**
|
||||
* Sets the fetchmode used to retrieve results.
|
||||
* Changing fetchmodes mid-result retrieval is supported (haven't encountered any drivers
|
||||
* that don't support that yet).
|
||||
* @param int $mode ResultSet::FETCHMODE_NUM or ResultSet::FETCHMODE_ASSOC (default).
|
||||
* @return void
|
||||
*/
|
||||
public function setFetchmode($mode);
|
||||
|
||||
/**
|
||||
* Gets the fetchmode used to retrieve results.
|
||||
* @return int ResultSet::FETCHMODE_NUM or ResultSet::FETCHMODE_ASSOC (default).
|
||||
*/
|
||||
public function getFetchmode();
|
||||
|
||||
/**
|
||||
* Whether assoc result keys get converted to lowercase for compatibility.
|
||||
*
|
||||
* This defaults to FALSE unless Creole::COMPAT_ASSOC_LOWER flag has been passed to connection.
|
||||
* This property is read-only since it must be set when connection is created. The
|
||||
* reason for this behavior is some drivers (e.g. SQLite) do the case conversions internally
|
||||
* based on a PHP ini value; it would not be possible to change the behavior from the ResultSet
|
||||
* (since query has already been executed).
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLowerAssocCase();
|
||||
|
||||
/**
|
||||
* Moves the internal cursor to the next position and fetches the row at that position.
|
||||
*
|
||||
* @return boolean <tt>true</tt> if success, <tt>false</tt> if no next record.
|
||||
* @throws SQLException on any driver-level errors.
|
||||
*/
|
||||
public function next();
|
||||
|
||||
/**
|
||||
* Moves the internal cursor to the previous position and fetches the
|
||||
* row at that position.
|
||||
*
|
||||
* @return boolean <tt>true</tt> if success, <tt>false</tt> if no previous record.
|
||||
* @throws SQLException - if unable to move to previous position
|
||||
* - if ResultSet doesn't support reverse scrolling
|
||||
*/
|
||||
public function previous();
|
||||
|
||||
/**
|
||||
* Moves the cursor a relative number of rows, either positive or negative and fetches
|
||||
* the row at that position.
|
||||
*
|
||||
* Attempting to move beyond the first/last row in the result set positions the cursor before/after
|
||||
* the first/last row and issues a Warning. Calling relative(0) is valid, but does not change the cursor
|
||||
* position.
|
||||
*
|
||||
* @param integer $offset
|
||||
* @return boolean <tt>true</tt> if cursor is on a row, <tt>false</tt> otherwise.
|
||||
* @throws SQLException - if unable to move to relative position
|
||||
* - if rel pos is negative & ResultSet doesn't support reverse scrolling
|
||||
*/
|
||||
public function relative($offset);
|
||||
|
||||
|
||||
/**
|
||||
* Moves the cursor to an absolute cursor position and fetches the row at that position.
|
||||
*
|
||||
* Attempting to move beyond the first/last row in the result set positions the cursor before/after
|
||||
* the first/last row and issues a Warning.
|
||||
*
|
||||
* @param integer $pos cursor position, first position is 1.
|
||||
* @return boolean <tt>true</tt> if cursor is on a row, <tt>false</tt> otherwise.
|
||||
* @throws SQLException - if unable to move to absolute position
|
||||
* - if position is before current pos & ResultSet doesn't support reverse scrolling
|
||||
*/
|
||||
public function absolute($pos);
|
||||
|
||||
/**
|
||||
* Moves cursor position WITHOUT FETCHING ROW AT THAT POSITION.
|
||||
*
|
||||
* Generally this method is for internal driver stuff (e.g. other methods like
|
||||
* absolute() or relative() might call this and then call next() to get the row).
|
||||
* This method is public to facilitate more advanced ResultSet scrolling tools
|
||||
* -- e.g. cleaner implimentation of ResultSetIterator.
|
||||
*
|
||||
* Some drivers will emulate seek() and not allow reverse seek (Oracle).
|
||||
*
|
||||
* Seek is 0-based, but seek() is only for moving to the space _before_ the record
|
||||
* that you want to read. I.e. if you seek(0) and then call next() you will have the
|
||||
* first row (i.e. same as calling first() or absolute(1)).
|
||||
*
|
||||
* <strong>IMPORTANT: You cannot rely on the return value of this method to know whether a given
|
||||
* record exists for reading. In some cases seek() will correctly return <code>false</code> if
|
||||
* the position doesn't exist, but in other drivers the seek is not performed until the
|
||||
* record is fetched. You can check the return value of absolute() if you need to know
|
||||
* whether a specific rec position is valid.</strong>
|
||||
*
|
||||
* @param int $rownum The cursor pos to seek to.
|
||||
* @return boolean true on success, false if unable to seek to specified record.
|
||||
* @throws SQLException if trying to seek backwards with a driver that doesn't
|
||||
* support reverse-scrolling
|
||||
*/
|
||||
public function seek($rownum);
|
||||
|
||||
/**
|
||||
* Move cursor to beginning of recordset.
|
||||
* @return boolean <tt>true</tt> on success or <tt>false</tt> if not found.
|
||||
* @throws SQLException - if unable to move to first position
|
||||
* - if not at first pos & ResultSet doesn't support reverse scrolling
|
||||
*/
|
||||
public function first();
|
||||
|
||||
/**
|
||||
* Move cursor to end of recordset.
|
||||
* @return boolean <tt>true</tt> on success or <tt>false</tt> if not found.
|
||||
* @throws SQLException - if unable to move to last position
|
||||
* - if unable to get num rows
|
||||
*/
|
||||
public function last();
|
||||
|
||||
/**
|
||||
* Sets cursort to before first record. This does not actually seek(), but
|
||||
* simply sets cursor pos to 0.
|
||||
* This is useful for inserting a record before the first in the set, etc.
|
||||
* @return void
|
||||
*/
|
||||
public function beforeFirst();
|
||||
|
||||
|
||||
/**
|
||||
* Sets cursort to after the last record. This does not actually seek(), but
|
||||
* simply sets the cursor pos to last + 1.
|
||||
* This [will be] useful for inserting a record after the last in the set,
|
||||
* when/if Creole supports updateable ResultSets.
|
||||
* @return void
|
||||
*/
|
||||
public function afterLast();
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether cursor is after the last record.
|
||||
* @return boolean
|
||||
* @throws SQLException on any driver-level error.
|
||||
*/
|
||||
public function isAfterLast();
|
||||
|
||||
/**
|
||||
* Checks whether cursor is before the first record.
|
||||
* @return boolean
|
||||
* @throws SQLException on any driver-level error.
|
||||
*/
|
||||
public function isBeforeFirst();
|
||||
|
||||
/**
|
||||
* Returns the current cursor position.
|
||||
* Cursor positions start at 0, but as soon as first row is fetched
|
||||
* cursor position is 1. (so first row is 1)
|
||||
* @return int
|
||||
*/
|
||||
public function getCursorPos();
|
||||
|
||||
/**
|
||||
* Gets current fields (assoc array).
|
||||
* @return array
|
||||
*/
|
||||
public function getRow();
|
||||
|
||||
/**
|
||||
* Get the number of rows in a result set.
|
||||
* @return int the number of rows
|
||||
* @throws SQLException - if unable to get a rowcount.
|
||||
*/
|
||||
public function getRecordCount();
|
||||
|
||||
/**
|
||||
* Frees the resources allocated for this result set.
|
||||
* Also empties any internal field array so that any calls to
|
||||
* get() method on closed ResultSet will result in "Invalid column" SQLException.
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
|
||||
/**
|
||||
* A generic get method returns unformatted (=string) value.
|
||||
* This returns the raw results from the database. Usually this will be a string, but some drivers
|
||||
* also can return objects (lob descriptors, etc) in certain cases.
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used) (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return mixed Usually expect a string.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function get($column);
|
||||
|
||||
/**
|
||||
* Reads a column as an array.
|
||||
* The value of the column is unserialized & returned as an array. The generic case of this function is
|
||||
* very PHP-specific. Other drivers (e.g. Postgres) will format values into their native array format.
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return array value or null if database returned null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getArray($column);
|
||||
|
||||
/**
|
||||
* Returns value translated to boolean.
|
||||
* Default is to map 0 => false, 1 => true, but some database drivers may override this behavior.
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return boolean value or null if database returned null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getBoolean($column);
|
||||
|
||||
/**
|
||||
* Returns Blob with contents of column value.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return Blob New Blob with data from column or null if database returned null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getBlob($column);
|
||||
|
||||
/**
|
||||
* Returns Clob with contents of column value.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return Clob New Clob object with data from column or null if database returned null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getClob($column);
|
||||
|
||||
/**
|
||||
* Return a formatted date.
|
||||
*
|
||||
* The default format for dates returned is preferred (in your locale, as specified using setlocale())
|
||||
* format w/o time (i.e. strftime("%x", $val)). Override this by specifying a format second parameter. You
|
||||
* can also specify a date()-style formatter; if you do, make sure there are no "%" symbols in your format string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @param string $format Date formatter for use w/ strftime() or date() (it will choose based on examination of format string)
|
||||
* If format is NULL, then the integer unix timestamp will be returned (no formatting performed).
|
||||
* @return mixed Formatted date, or integer unix timestamp (using 00:00:00 for time) if $format was null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getDate($column, $format = '%x');
|
||||
|
||||
/**
|
||||
* Returns value cast as a float (in PHP this is same as double).
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return float value or null if database returned null
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getFloat($column);
|
||||
|
||||
/**
|
||||
* Returns value cast as integer.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return int value or null if database returned null
|
||||
* @see getInteger()
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getInt($column);
|
||||
|
||||
/**
|
||||
* Returns value cast as string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return string value or null if database returned null
|
||||
* @see get()
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getString($column);
|
||||
|
||||
/**
|
||||
* Return a formatted time.
|
||||
*
|
||||
* The default format for times returned is preferred (in your locale, as specified using setlocale())
|
||||
* format w/o date (i.e. strftime("%X", $val)). Override this by specifying a format second parameter. You
|
||||
* can also specify a date()-style formatter; if you do, make sure there are no "%" symbols in your format string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @param string $format Date formatter for use w/ strftime() or date() (it will choose based on examination of format string)
|
||||
* If format is NULL, then the integer unix timestamp will be returned (no formatting performed).
|
||||
* @return mixed Formatted time, or integer unix timestamp (using today's date) if $format was null.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getTime($column, $format = '%X');
|
||||
|
||||
/**
|
||||
* Return a formatted timestamp.
|
||||
*
|
||||
* The default format for timestamp is ISO standard YYYY-MM-DD HH:MM:SS (i.e. date('Y-m-d H:i:s', $val).
|
||||
* Override this by specifying a format second parameter. You can also specify a strftime()-style formatter.
|
||||
*
|
||||
* Hint: if you want to get the unix timestamp use the "U" formatter string.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @param string $format Date formatter for use w/ strftime() or date() (it will choose based on examination of format string)
|
||||
* If format is NULL, then the integer unix timestamp will be returned (no formatting performed).
|
||||
* @return mixed Formatted timestamp, or integer unix timestamp (if $format was null)
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getTimestamp($column, $format = 'Y-m-d H:i:s');
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ResultSetIterator.php,v 1.3 2004/03/15 17:47:45 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Basic ResultSet Iterator.
|
||||
*
|
||||
* This can be returned by your class's getIterator() method, but of course
|
||||
* you can also implement your own (e.g. to get better performance, by using direct
|
||||
* driver calls and avoiding other side-effects inherent in ResultSet scrolling
|
||||
* functions -- e.g. beforeFirst() / afterLast(), etc.).
|
||||
*
|
||||
* Important: ResultSet iteration does rewind the resultset if it is not at the
|
||||
* start. Not all drivers support reverse scrolling, so this may result in an
|
||||
* exception in some cases (Oracle).
|
||||
*
|
||||
* Developer note:
|
||||
* The implementation of this class is a little weird because it fetches the
|
||||
* array _early_ in order to answer valid() w/o needing to know total num
|
||||
* of fields. Remember the way iterators work:
|
||||
* <code>
|
||||
* $it = $obj->getIterator();
|
||||
* for($it->rewind(); $it->valid(); $it->next()) {
|
||||
* $key = $it->current();
|
||||
* $val = $it->key();
|
||||
* echo "$key = $val\n";
|
||||
* }
|
||||
* unset($it);
|
||||
* </code>
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole
|
||||
*/
|
||||
class ResultSetIterator implements Iterator {
|
||||
|
||||
private $rs;
|
||||
|
||||
/**
|
||||
* Construct the iterator.
|
||||
* @param ResultSet $rs
|
||||
*/
|
||||
public function __construct(ResultSet $rs)
|
||||
{
|
||||
$this->rs = $rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* If not at start of resultset, this method will call seek(0).
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
function rewind()
|
||||
{
|
||||
if (!$this->rs->isBeforeFirst()) {
|
||||
$this->rs->seek(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks to see whether there are more results
|
||||
* by advancing the cursor position.
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
function valid()
|
||||
{
|
||||
return $this->rs->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cursor position.
|
||||
* @return int
|
||||
*/
|
||||
function key()
|
||||
{
|
||||
return $this->rs->getCursorPos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row (assoc array) at current cursor pos.
|
||||
* @return array
|
||||
*/
|
||||
function current()
|
||||
{
|
||||
return $this->rs->getRow();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does not actually do anything since we have already advanced
|
||||
* the cursor pos in valid().
|
||||
* @see valid()
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLException.php,v 1.10 2004/03/20 04:16:49 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A class for handling database-related errors.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.10 $
|
||||
* @package creole
|
||||
*/
|
||||
class SQLException extends Exception {
|
||||
|
||||
/** Information that provides additional information for context of Exception (e.g. SQL statement or DSN). */
|
||||
protected $userInfo;
|
||||
|
||||
/** Native RDBMS error string */
|
||||
protected $nativeError;
|
||||
|
||||
/**
|
||||
* Constructs a SQLException.
|
||||
* @param string $msg Error message
|
||||
* @param string $native Native DB error message.
|
||||
* @param string $userinfo More info, e.g. the SQL statement or the connection string that caused the error.
|
||||
*/
|
||||
public function __construct($msg, $native = null, $userinfo = null)
|
||||
{
|
||||
parent::__construct($msg);
|
||||
if ($native !== null) {
|
||||
$this->setNativeError($native);
|
||||
}
|
||||
if ($userinfo !== null) {
|
||||
$this->setUserInfo($userinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets additional user / debug information for this error.
|
||||
*
|
||||
* @param array $info
|
||||
* @return void
|
||||
*/
|
||||
public function setUserInfo($info)
|
||||
{
|
||||
$this->userInfo = $info;
|
||||
$this->message .= " [User Info: " .$this->userInfo . "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional / debug information for this error.
|
||||
*
|
||||
* @return array hash of user info properties.
|
||||
*/
|
||||
public function getUserInfo()
|
||||
{
|
||||
return $this->userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets driver native error message.
|
||||
*
|
||||
* @param string $info
|
||||
* @return void
|
||||
*/
|
||||
public function setNativeError($msg)
|
||||
{
|
||||
$this->nativeError = $msg;
|
||||
$this->message .= " [Native Error: " .$this->nativeError . "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets driver native error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNativeError()
|
||||
{
|
||||
return $this->nativeError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method only exists right now for easier compatibility w/ PHPUnit!
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->getMessage();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: Statement.php,v 1.17 2004/03/20 04:16:49 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents a SQL statement.
|
||||
*
|
||||
* This class is very generic and has no driver-specific implementations. In fact,
|
||||
* it wouldn't be possible to have driver-specific classes, since PHP doesn't support
|
||||
* multiple inheritance. I.e. you couldn't have MySQLPreparedStatement that extended
|
||||
* both the abstract PreparedStatement class and the MySQLStatement class. In Java
|
||||
* this isn't a concern since PreparedStatement is an interface, not a class.
|
||||
*
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.17 $
|
||||
* @package creole
|
||||
*/
|
||||
interface Statement {
|
||||
|
||||
/**
|
||||
* Sets the maximum number of rows to return from db.
|
||||
* This will affect the SQL if the RDBMS supports native LIMIT; if not,
|
||||
* it will be emulated. Limit only applies to queries (not update sql).
|
||||
* @param int $v Maximum number of rows or 0 for all rows.
|
||||
* @return void
|
||||
*/
|
||||
public function setLimit($v);
|
||||
|
||||
/**
|
||||
* Returns the maximum number of rows to return or 0 for all.
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit();
|
||||
|
||||
/**
|
||||
* Sets the start row.
|
||||
* This will affect the SQL if the RDBMS supports native OFFSET; if not,
|
||||
* it will be emulated. Offset only applies to queries (not update) and
|
||||
* only is evaluated when LIMIT is set!
|
||||
* @param int $v
|
||||
* @return void
|
||||
*/
|
||||
public function setOffset($v);
|
||||
|
||||
/**
|
||||
* Returns the start row.
|
||||
* Offset only applies when Limit is set!
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset();
|
||||
|
||||
/**
|
||||
* Free resources associated with this statement.
|
||||
* Some drivers will need to implement this method to free
|
||||
* database result resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
|
||||
/**
|
||||
* Generic execute() function has to check to see whether SQL is an update or select query.
|
||||
*
|
||||
* If you already know whether it's a SELECT or an update (manipulating) SQL, then use
|
||||
* the appropriate method, as this one will incurr overhead to check the SQL.
|
||||
*
|
||||
* @param int $fetchmode Fetchmode (only applies to queries).
|
||||
* @return boolean True if it is a result set, false if not or if no more results (this is identical to JDBC return val).
|
||||
* @throws SQLException
|
||||
*/
|
||||
public function execute($sql, $fetchmode = null);
|
||||
|
||||
/**
|
||||
* Get result set.
|
||||
* This assumes that the last thing done was an executeQuery() or an execute()
|
||||
* with SELECT-type query.
|
||||
*
|
||||
* @return RestultSet (or null if none)
|
||||
*/
|
||||
public function getResultSet();
|
||||
|
||||
/**
|
||||
* Get update count.
|
||||
*
|
||||
* @return int Number of records affected, or <code>null</code> if not applicable.
|
||||
*/
|
||||
public function getUpdateCount();
|
||||
|
||||
/**
|
||||
* Executes the SQL query in this PreparedStatement object and returns the resultset generated by the query.
|
||||
*
|
||||
* @param string $sql This method may optionally be called with the SQL statement.
|
||||
* @param int $fetchmode The mode to use when fetching the results (e.g. ResultSet::FETCHMODE_NUM, ResultSet::FETCHMODE_ASSOC).
|
||||
* @return object Creole::ResultSet
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null);
|
||||
|
||||
/**
|
||||
* Executes the SQL INSERT, UPDATE, or DELETE statement in this PreparedStatement object.
|
||||
*
|
||||
* @param string $sql This method may optionally be called with the SQL statement.
|
||||
* @return int Number of affected rows (or 0 for drivers that return nothing).
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public function executeUpdate($sql);
|
||||
|
||||
/**
|
||||
* Gets next result set (if this behavior is supported by driver).
|
||||
* Some drivers (e.g. MSSQL) support returning multiple result sets -- e.g.
|
||||
* from stored procedures.
|
||||
*
|
||||
* This function also closes any current restult set.
|
||||
*
|
||||
* Default behavior is for this function to return false. Driver-specific
|
||||
* implementations of this class can override this method if they actually
|
||||
* support multiple result sets.
|
||||
*
|
||||
* @return boolean True if there is another result set, otherwise false.
|
||||
*/
|
||||
public function getMoreResults();
|
||||
|
||||
/**
|
||||
* Gets the db Connection that created this statement.
|
||||
* @return Connection
|
||||
*/
|
||||
public function getConnection();
|
||||
|
||||
}
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ConnectionCommon.php,v 1.5 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that contains some shared/default information for connections. Classes may wish to extend this so
|
||||
* as not to worry about the sleep/wakeup methods, etc.
|
||||
*
|
||||
* In reality this class is not very useful yet, so there's not much incentive for drivers to extend this.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.5 $
|
||||
* @package creole.common
|
||||
*/
|
||||
abstract class ConnectionCommon {
|
||||
|
||||
// Constants that define transaction isolation levels.
|
||||
// [We don't have any code using these yet, so there's no need
|
||||
// to initialize these values at this point.]
|
||||
// const TRANSACTION_NONE = 0;
|
||||
// const TRANSACTION_READ_UNCOMMITTED = 1;
|
||||
// const TRANSACTION_READ_COMMITTED = 2;
|
||||
// const TRANSACTION_REPEATABLE_READ = 3;
|
||||
// const TRANSACTION_SERIALIZABLE = 4;
|
||||
|
||||
/**
|
||||
* The depth level of current transaction.
|
||||
* @var int
|
||||
*/
|
||||
protected $transactionOpcount = 0;
|
||||
|
||||
/**
|
||||
* DB connection resource id.
|
||||
* @var resource
|
||||
*/
|
||||
protected $dblink;
|
||||
|
||||
/**
|
||||
* Array hash of connection properties.
|
||||
* @var array
|
||||
*/
|
||||
protected $dsn;
|
||||
|
||||
/**
|
||||
* Flags (e.g. Connection::PERSISTENT) for current connection.
|
||||
* @var int
|
||||
*/
|
||||
protected $flags = 0;
|
||||
|
||||
/**
|
||||
* This "magic" method is invoked upon serialize() and works in tandem with the __wakeup()
|
||||
* method to ensure that your database connection is serializable.
|
||||
*
|
||||
* This method returns an array containing the names of any members of your class
|
||||
* which need to be serialized in order to allow the class to re-connect to the database
|
||||
* when it is unserialized.
|
||||
*
|
||||
* <p>
|
||||
* Developers:
|
||||
*
|
||||
* Note that you cannot serialize resources (connection links) and expect them to
|
||||
* be valid when you unserialize. For this reason, you must re-connect to the database in the
|
||||
* __wakeup() method.
|
||||
*
|
||||
* It's up to your class implimentation to ensure that the necessary data is serialized.
|
||||
* You probably at least need to serialize:
|
||||
*
|
||||
* (1) the DSN array used by connect() method
|
||||
* (2) Any flags that were passed to the connection
|
||||
* (3) Possibly the autocommit state
|
||||
*
|
||||
* @return array The class variable names that should be serialized.
|
||||
* @see __wakeup()
|
||||
* @see DriverManager::getConnection()
|
||||
* @see DatabaseInfo::__sleep()
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array('dsn', 'flags');
|
||||
}
|
||||
|
||||
/**
|
||||
* This "magic" method is invoked upon unserialize().
|
||||
* This method will re-connects to the database using the information that was
|
||||
* stored using the __sleep() method.
|
||||
* @see __sleep()
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->connect($this->dsn, $this->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getResource()
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->dblink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDSN()
|
||||
*/
|
||||
public function getDSN() {
|
||||
return $this->dsn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getFlags()
|
||||
*/
|
||||
public function getFlags()
|
||||
{
|
||||
return $this->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CallableStatement object for calling database stored procedures.
|
||||
*
|
||||
* @param string $sql
|
||||
* @return CallableStatement
|
||||
*/
|
||||
public function prepareCall($sql)
|
||||
{
|
||||
throw new SQLException("Current driver does not support stored procedures using CallableStatement.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Driver classes should override this if they support transactions.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function supportsNestedTrans()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
if ($this->transactionOpcount === 0 || $this->supportsNestedTrans()) {
|
||||
$this->beginTrans();
|
||||
}
|
||||
$this->transactionOpcount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if ($this->transactionOpcount > 0) {
|
||||
if ($this->transactionOpcount == 1 || $this->supportsNestedTrans()) {
|
||||
$this->commitTrans();
|
||||
}
|
||||
$this->transactionOpcount--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if ($this->transactionOpcount > 0) {
|
||||
if ($this->transactionOpcount == 1 || $this->supportsNestedTrans()) {
|
||||
$this->rollbackTrans();
|
||||
}
|
||||
$this->transactionOpcount--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable automatic commits.
|
||||
*
|
||||
* Pushes SQLWarning onto $warnings stack if the autocommit value is being changed mid-transaction. This function
|
||||
* is overridden by driver classes so that they can perform the necessary begin/end transaction SQL.
|
||||
*
|
||||
* If auto-commit is being set to TRUE, then the current transaction will be committed immediately.
|
||||
*
|
||||
* @param boolean $bit New value for auto commit.
|
||||
* @return void
|
||||
*/
|
||||
public function setAutoCommit($bit)
|
||||
{
|
||||
if ($this->transactionOpcount > 0) {
|
||||
trigger_error("Changing autocommit in mid-transaction; committing " . $this->transactionOpcount . " uncommitted statements.", E_USER_WARNING);
|
||||
}
|
||||
|
||||
if (!$bit) {
|
||||
$this->begin();
|
||||
}
|
||||
else {
|
||||
$this->commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get auto-commit status.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getAutoCommit()
|
||||
{
|
||||
return ($this->transactionOpcount == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin new transaction.
|
||||
* Driver classes should override this method if they support transactions.
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* Driver classes should override this method if they support transactions.
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* Driver classes should override this method if they support transactions.
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if connection is closed.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return !empty($this->dblink);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,640 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PreparedStatementCommon.php,v 1.16 2005/11/13 01:30:00 gamr 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents a shared code for handling emulated pre-compiled statements.
|
||||
*
|
||||
* Many drivers do not take advantage of pre-compiling SQL statements; for these
|
||||
* cases the precompilation is emulated. This emulation comes with slight penalty involved
|
||||
* in parsing the queries, but provides other benefits such as a cleaner object model and ability
|
||||
* to work with BLOB and CLOB values w/o needing special LOB-specific routines.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.16 $
|
||||
* @package creole.common
|
||||
*/
|
||||
abstract class PreparedStatementCommon {
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
* @var Connection
|
||||
*/
|
||||
protected $conn;
|
||||
|
||||
/**
|
||||
* Max rows to retrieve from DB.
|
||||
* @var int
|
||||
*/
|
||||
protected $limit = 0;
|
||||
|
||||
/**
|
||||
* Offset at which to start processing DB rows.
|
||||
* "Skip X rows"
|
||||
* @var int
|
||||
*/
|
||||
protected $offset = 0;
|
||||
|
||||
/**
|
||||
* The SQL this class operates on.
|
||||
* @var string
|
||||
*/
|
||||
protected $sql;
|
||||
|
||||
/**
|
||||
* Possibly contains a cached prepared SQL Statement.
|
||||
* Gives an early out to replaceParams if the same
|
||||
* query is run multiple times without changing the
|
||||
* params.
|
||||
* @var string
|
||||
*/
|
||||
protected $sql_cache;
|
||||
|
||||
/**
|
||||
* Flag to set if the cache is upto date or not
|
||||
* @var boolean
|
||||
*/
|
||||
protected $sql_cache_valid = false;
|
||||
|
||||
/**
|
||||
* The string positions of the parameters in the SQL.
|
||||
* @var array
|
||||
*/
|
||||
protected $positions;
|
||||
|
||||
|
||||
/**
|
||||
* Number of positions (simply to save processing).
|
||||
* @var int
|
||||
*/
|
||||
protected $positionsCount;
|
||||
|
||||
/**
|
||||
* Map of index => value for bound params.
|
||||
* @var array string[]
|
||||
*/
|
||||
protected $boundInVars = array();
|
||||
|
||||
/**
|
||||
* Temporarily hold a ResultSet object after an execute() query.
|
||||
* @var ResultSet
|
||||
*/
|
||||
protected $resultSet;
|
||||
|
||||
/**
|
||||
* Temporary hold the affected row cound after an execute() query.
|
||||
* @var int
|
||||
*/
|
||||
protected $updateCount;
|
||||
|
||||
/**
|
||||
* Create new prepared statement instance.
|
||||
*
|
||||
* @param object $conn Connection object
|
||||
* @param string $sql The SQL to work with.
|
||||
* @param array $positions The positions in SQL of ?'s.
|
||||
* @param restult $stmt If the driver supports prepared queries, then $stmt will contain the statement to use.
|
||||
*/
|
||||
public function __construct(Connection $conn, $sql)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->sql = $sql;
|
||||
|
||||
$this->positions = $this->parseQuery ( $sql );
|
||||
// save processing later in cases where we may repeatedly exec statement
|
||||
$this->positionsCount = count ( $this->positions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the SQL query for ? positions
|
||||
*
|
||||
* @param string $sql The query to process
|
||||
* @return array Positions from the start of the string that ?'s appear at
|
||||
*/
|
||||
protected function parseQuery ( $sql )
|
||||
{
|
||||
|
||||
$positions = array();
|
||||
// match anything ? ' " or \ in $sql with an early out if we find nothing
|
||||
if ( preg_match_all ( '([\?]|[\']|[\"]|[\\\])', $sql, $matches, PREG_OFFSET_CAPTURE ) !== 0 ) {
|
||||
$matches = $matches['0'];
|
||||
$open = NULL;
|
||||
// go thru all our matches and see what we can find
|
||||
for ( $i = 0, $j = count ( $matches ); $i < $j; $i++ ) {
|
||||
switch ( $matches[$i]['0'] ) {
|
||||
// if we already have an open " or ' then check if this is the end
|
||||
// to close it or not
|
||||
case $open:
|
||||
$open = NULL;
|
||||
break;
|
||||
// we have a quote, set ourselves open
|
||||
case '"':
|
||||
case "'":
|
||||
$open = $matches[$i]['0'];
|
||||
break;
|
||||
// check if it is an escaped quote and skip if it is
|
||||
case '\\':
|
||||
$next_match = $matches[$i+1]['0'];
|
||||
if ( $next_match === '"' || $next_match === "'" ) {
|
||||
$i++;
|
||||
}
|
||||
unset ( $next_match );
|
||||
break;
|
||||
// we found a ?, check we arent in an open "/' first and
|
||||
// add it to the position list if we arent
|
||||
default:
|
||||
if ( $open === NULL ) {
|
||||
$positions[] = $matches[$i]['1'];
|
||||
}
|
||||
}
|
||||
unset ( $matches[$i] );
|
||||
}
|
||||
unset ( $open, $matches, $i, $j );
|
||||
}
|
||||
|
||||
return $positions;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setLimit()
|
||||
*/
|
||||
public function setLimit($v)
|
||||
{
|
||||
$this->limit = (int) $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::getLimit()
|
||||
*/
|
||||
public function getLimit()
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setOffset()
|
||||
*/
|
||||
public function setOffset($v)
|
||||
{
|
||||
$this->offset = (int) $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::getOffset()
|
||||
*/
|
||||
public function getOffset()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::getResultSet()
|
||||
*/
|
||||
public function getResultSet()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::getUpdateCount()
|
||||
*/
|
||||
public function getUpdateCount()
|
||||
{
|
||||
return $this->updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::getMoreResults()
|
||||
*/
|
||||
public function getMoreResults()
|
||||
{
|
||||
if ($this->resultSet) $this->resultSet->close();
|
||||
$this->resultSet = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::getConnection()
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Statement resources do not exist for emulated prepared statements,
|
||||
* so this just returns <code>null</code>.
|
||||
* @return null
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nothing to close for emulated prepared statements.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces placeholders with the specified parameter values in the SQL.
|
||||
*
|
||||
* This is for emulated prepared statements.
|
||||
*
|
||||
* @return string New SQL statement with parameters replaced.
|
||||
* @throws SQLException - if param not bound.
|
||||
*/
|
||||
protected function replaceParams()
|
||||
{
|
||||
// early out if we still have the same query ready
|
||||
if ( $this->sql_cache_valid === true ) {
|
||||
return $this->sql_cache;
|
||||
}
|
||||
|
||||
// Default behavior for this function is to behave in 'emulated' mode.
|
||||
$sql = '';
|
||||
$last_position = 0;
|
||||
|
||||
for ($position = 0; $position < $this->positionsCount; $position++) {
|
||||
if (!isset($this->boundInVars[$position + 1])) {
|
||||
throw new SQLException('Replace params: undefined query param: ' . ($position + 1));
|
||||
}
|
||||
$current_position = $this->positions[$position];
|
||||
$sql .= substr($this->sql, $last_position, $current_position - $last_position);
|
||||
$sql .= $this->boundInVars[$position + 1];
|
||||
$last_position = $current_position + 1;
|
||||
}
|
||||
// append the rest of the query
|
||||
$sql .= substr($this->sql, $last_position);
|
||||
|
||||
// just so we dont touch anything with a blob/clob
|
||||
if ( strlen ( $sql ) > 2048 ) {
|
||||
$this->sql_cache = $sql;
|
||||
$this->sql_cache_valid = true;
|
||||
return $this->sql_cache;
|
||||
} else {
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the SQL query in this PreparedStatement object and returns the resultset generated by the query.
|
||||
* We support two signatures for this method:
|
||||
* - $stmt->executeQuery(ResultSet::FETCHMODE_NUM);
|
||||
* - $stmt->executeQuery(array($param1, $param2), ResultSet::FETCHMODE_NUM);
|
||||
* @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;
|
||||
}
|
||||
|
||||
foreach ( (array) $params as $i=>$param ) {
|
||||
$this->set ( $i + 1, $param );
|
||||
unset ( $i, $param );
|
||||
}
|
||||
unset ( $params );
|
||||
|
||||
$this->updateCount = null; // reset
|
||||
$sql = $this->replaceParams();
|
||||
|
||||
if ($this->limit > 0 || $this->offset > 0) {
|
||||
$this->conn->applyLimit($sql, $this->offset, $this->limit);
|
||||
}
|
||||
|
||||
$this->resultSet = $this->conn->executeQuery($sql, $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)
|
||||
{
|
||||
foreach ( (array) $params as $i=>$param ) {
|
||||
$this->set ( $i + 1, $param );
|
||||
unset ( $i, $param );
|
||||
}
|
||||
unset ( $params );
|
||||
|
||||
if($this->resultSet) $this->resultSet->close();
|
||||
$this->resultSet = null; // reset
|
||||
$sql = $this->replaceParams();
|
||||
$this->updateCount = $this->conn->executeUpdate($sql);
|
||||
return $this->updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes special characters (usu. quotes) using native driver function.
|
||||
* @param string $str The input string.
|
||||
* @return string The escaped string.
|
||||
*/
|
||||
abstract protected function escape($str);
|
||||
|
||||
/**
|
||||
* A generic set method.
|
||||
*
|
||||
* You can use this if you don't want to concern yourself with the details. It involves
|
||||
* slightly more overhead than the specific settesr, since it grabs the PHP type to determine
|
||||
* which method makes most sense.
|
||||
*
|
||||
* @param int $paramIndex
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
function set($paramIndex, $value)
|
||||
{
|
||||
$type = gettype($value);
|
||||
if ($type == "object") {
|
||||
if (is_a($value, 'Blob')) {
|
||||
$this->setBlob($paramIndex, $value);
|
||||
} elseif (is_a($value, 'Clob')) {
|
||||
$this->setClob($paramIndex, $value);
|
||||
} elseif (is_a($value, 'Date')) {
|
||||
// can't be sure if the column type is a DATE, TIME, or TIMESTAMP column
|
||||
// we'll just use TIMESTAMP by default; hopefully DB won't complain (if
|
||||
// it does, then this method just shouldn't be used).
|
||||
$this->setTimestamp($paramIndex, $value);
|
||||
} else {
|
||||
throw new SQLException("Unsupported object type passed to set(): " . get_class($value));
|
||||
}
|
||||
} else {
|
||||
switch ( $type ) {
|
||||
case 'integer':
|
||||
$type = 'int';
|
||||
break;
|
||||
case 'double':
|
||||
$type = 'float';
|
||||
break;
|
||||
}
|
||||
$setter = 'set' . ucfirst($type); // PHP types are case-insensitive, but we'll do this in case that change
|
||||
if ( method_exists ( $this, $setter ) ) {
|
||||
$this->$setter($paramIndex, $value);
|
||||
} else {
|
||||
throw new SQLException ( "Unsupported datatype passed to set(): " . $type );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an array.
|
||||
* Unless a driver-specific method is used, this means simply serializing
|
||||
* the passed parameter and storing it as a string.
|
||||
* @param int $paramIndex
|
||||
* @param array $value
|
||||
* @return void
|
||||
*/
|
||||
function setArray($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape(serialize($value)) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a boolean value.
|
||||
* Default behavior is true = 1, false = 0.
|
||||
* @param int $paramIndex
|
||||
* @param boolean $value
|
||||
* @return void
|
||||
*/
|
||||
function setBoolean($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = (int) $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setBlob()
|
||||
*/
|
||||
function setBlob($paramIndex, $blob)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($blob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
// they took magic __toString() out of PHP5.0.0; this sucks
|
||||
if (is_object($blob)) {
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape($blob->__toString()) . "'";
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape($blob) . "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setClob()
|
||||
*/
|
||||
function setClob($paramIndex, $clob)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($clob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
// they took magic __toString() out of PHP5.0.0; this sucks
|
||||
if (is_object($clob)) {
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape($clob->__toString()) . "'";
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape($clob) . "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
function setDate($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
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] = "'" . $this->escape($value) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param double $value
|
||||
* @return void
|
||||
*/
|
||||
function setDecimal($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = (float) $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param double $value
|
||||
* @return void
|
||||
*/
|
||||
function setDouble($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = (double) $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param float $value
|
||||
* @return void
|
||||
*/
|
||||
function setFloat($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = (float) $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param int $value
|
||||
* @return void
|
||||
*/
|
||||
function setInt($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = (int) $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for setInt()
|
||||
* @param int $paramIndex
|
||||
* @param int $value
|
||||
*/
|
||||
function setInteger($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
$this->setInt($paramIndex, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @return void
|
||||
*/
|
||||
function setNull($paramIndex)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
$this->boundInVars[$paramIndex] = 'NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
function setString($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
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] = "'" . $this->escape($value->__toString()) . "'";
|
||||
} else {
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape((string)$value) . "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
function setTime($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if ( is_numeric ( $value ) ) {
|
||||
$value = date ('H:i:s', $value );
|
||||
} elseif ( is_object ( $value ) ) {
|
||||
$value = date ('H:i:s', $value->getTime ( ) );
|
||||
}
|
||||
$this->boundInVars [ $paramIndex ] = "'" . $this->escape ( $value ) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
function setTimestamp($paramIndex, $value)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
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] = "'".$this->escape($value)."'";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,447 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ResultSetCommon.php,v 1.9 2006/01/17 19:44:38 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class implements many shared or common methods needed by resultset drivers.
|
||||
*
|
||||
* This class may (optionally) be extended by driver classes simply to make it easier
|
||||
* to create driver classes. This is also useful in the early stages of Creole development
|
||||
* as it means that API changes affect fewer files. As Creole matures/stabalizes having
|
||||
* a common class may become less useful, as drivers may have their own ways of doing things
|
||||
* (and we'll have a solid unit test framework to make sure drivers conform to the API
|
||||
* described by the interfaces).
|
||||
*
|
||||
* The get*() methods in this class will format values before returning them. Note
|
||||
* that if they will return <code>null</code> if the database returned <code>NULL</code>
|
||||
* which makes these functions easier to use than simply typecasting the values from the
|
||||
* db. If the requested column does not exist than an exception (SQLException) will be thrown.
|
||||
*
|
||||
* <code>
|
||||
* $rs = $conn->executeQuery("SELECT MAX(stamp) FROM event", ResultSet::FETCHMODE_NUM);
|
||||
* $rs->next();
|
||||
*
|
||||
* $max_stamp = $rs->getTimestamp(1, "d/m/Y H:i:s");
|
||||
* // $max_stamp will be date string or null if no MAX(stamp) was found
|
||||
*
|
||||
* $max_stamp = $rs->getTimestamp("max(stamp)", "d/m/Y H:i:s");
|
||||
* // will THROW EXCEPTION, because the resultset was fetched using numeric indexing
|
||||
* // SQLException: Invalid resultset column: max(stamp)
|
||||
* </code>
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.9 $
|
||||
* @package creole.common
|
||||
*/
|
||||
abstract class ResultSetCommon {
|
||||
|
||||
/**
|
||||
* The fetchmode for this recordset.
|
||||
* @var int
|
||||
*/
|
||||
protected $fetchmode;
|
||||
|
||||
/**
|
||||
* DB connection.
|
||||
* @var Connection
|
||||
*/
|
||||
protected $conn;
|
||||
|
||||
/**
|
||||
* Resource identifier used for native result set handling.
|
||||
* @var resource
|
||||
*/
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* The current cursor position (row number). First row is 1. Before first row is 0.
|
||||
* @var int
|
||||
*/
|
||||
protected $cursorPos = 0;
|
||||
|
||||
/**
|
||||
* The current unprocessed record/row from the db.
|
||||
* @var array
|
||||
*/
|
||||
protected $fields;
|
||||
|
||||
/**
|
||||
* Whether to convert assoc col case.
|
||||
* @var boolean
|
||||
*/
|
||||
protected $lowerAssocCase = false;
|
||||
|
||||
/**
|
||||
* Whether to apply rtrim() to strings.
|
||||
* @var boolean
|
||||
*/
|
||||
protected $rtrimString = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct(Connection $conn, $result, $fetchmode = null)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->result = $result;
|
||||
if ($fetchmode !== null) {
|
||||
$this->fetchmode = $fetchmode;
|
||||
} else {
|
||||
$this->fetchmode = ResultSet::FETCHMODE_ASSOC; // default
|
||||
}
|
||||
$this->lowerAssocCase = (($conn->getFlags() & Creole::COMPAT_ASSOC_LOWER) === Creole::COMPAT_ASSOC_LOWER);
|
||||
$this->rtrimString = (($conn->getFlags() & Creole::COMPAT_RTRIM_STRING) === Creole::COMPAT_RTRIM_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* Free db result resource.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getIterator()
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
require_once 'creole/ResultSetIterator.php';
|
||||
return new ResultSetIterator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getResource()
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::isLowereAssocCase()
|
||||
*/
|
||||
public function isLowerAssocCase()
|
||||
{
|
||||
return $this->lowerAssocCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::setFetchmode()
|
||||
*/
|
||||
public function setFetchmode($mode)
|
||||
{
|
||||
$this->fetchmode = $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getFetchmode()
|
||||
*/
|
||||
public function getFetchmode()
|
||||
{
|
||||
return $this->fetchmode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::previous()
|
||||
*/
|
||||
public function previous()
|
||||
{
|
||||
// Go back 2 spaces so that we can then advance 1 space.
|
||||
$ok = $this->seek($this->cursorPos - 2);
|
||||
if ($ok === false) {
|
||||
$this->beforeFirst();
|
||||
return false;
|
||||
}
|
||||
return $this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::isBeforeFirst()
|
||||
*/
|
||||
public function relative($offset)
|
||||
{
|
||||
// which absolute row number are we seeking
|
||||
$pos = $this->cursorPos + ($offset - 1);
|
||||
$ok = $this->seek($pos);
|
||||
|
||||
if ($ok === false) {
|
||||
if ($pos < 0) {
|
||||
$this->beforeFirst();
|
||||
} else {
|
||||
$this->afterLast();
|
||||
}
|
||||
} else {
|
||||
$ok = $this->next();
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::absolute()
|
||||
*/
|
||||
public function absolute($pos)
|
||||
{
|
||||
$ok = $this->seek( $pos - 1 ); // compensate for next() factor
|
||||
if ($ok === false) {
|
||||
if ($pos - 1 < 0) {
|
||||
$this->beforeFirst();
|
||||
} else {
|
||||
$this->afterLast();
|
||||
}
|
||||
} else {
|
||||
$ok = $this->next();
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::first()
|
||||
*/
|
||||
public function first()
|
||||
{
|
||||
if($this->cursorPos !== 0) { $this->seek(0); }
|
||||
return $this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::last()
|
||||
*/
|
||||
public function last()
|
||||
{
|
||||
if($this->cursorPos !== ($last = $this->getRecordCount() - 1)) {
|
||||
$this->seek( $last );
|
||||
}
|
||||
return $this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::beforeFirst()
|
||||
*/
|
||||
public function beforeFirst()
|
||||
{
|
||||
$this->cursorPos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::afterLast()
|
||||
*/
|
||||
public function afterLast()
|
||||
{
|
||||
$this->cursorPos = $this->getRecordCount() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::isAfterLast()
|
||||
*/
|
||||
public function isAfterLast()
|
||||
{
|
||||
return ($this->cursorPos === $this->getRecordCount() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::isBeforeFirst()
|
||||
*/
|
||||
public function isBeforeFirst()
|
||||
{
|
||||
return ($this->cursorPos === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getCursorPos()
|
||||
*/
|
||||
public function getCursorPos()
|
||||
{
|
||||
return $this->cursorPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getRow()
|
||||
*/
|
||||
public function getRow()
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::get()
|
||||
*/
|
||||
public function get($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
return $this->fields[$idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getArray()
|
||||
*/
|
||||
public function getArray($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
return (array) unserialize($this->fields[$idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getBoolean()
|
||||
*/
|
||||
public function getBoolean($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
return (boolean) $this->fields[$idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getBlob()
|
||||
*/
|
||||
public function getBlob($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
require_once 'creole/util/Blob.php';
|
||||
$b = new Blob();
|
||||
$b->setContents($this->fields[$idx]);
|
||||
return $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getClob()
|
||||
*/
|
||||
public function getClob($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
require_once 'creole/util/Clob.php';
|
||||
$c = new Clob();
|
||||
$c->setContents($this->fields[$idx]);
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getDate()
|
||||
*/
|
||||
public function getDate($column, $format = '%x')
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
$ts = strtotime($this->fields[$idx]);
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
throw new SQLException("Unable to convert value at column " . $column . " to timestamp: " . $this->fields[$idx]);
|
||||
}
|
||||
if ($format === null) {
|
||||
return $ts;
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getFloat()
|
||||
*/
|
||||
public function getFloat($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
return (float) $this->fields[$idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getInt()
|
||||
*/
|
||||
public function getInt($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
return (int) $this->fields[$idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getString()
|
||||
*/
|
||||
public function getString($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
return ($this->rtrimString ? rtrim($this->fields[$idx]) : (string) $this->fields[$idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getTime()
|
||||
*/
|
||||
public function getTime($column, $format = '%X')
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
|
||||
$ts = strtotime($this->fields[$idx]);
|
||||
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
throw new SQLException("Unable to convert value at column " . (is_int($column) ? $column + 1 : $column) . " to timestamp: " . $this->fields[$idx]);
|
||||
}
|
||||
if ($format === null) {
|
||||
return $ts;
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getTimestamp()
|
||||
*/
|
||||
public function getTimestamp($column, $format = 'Y-m-d H:i:s')
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
|
||||
$ts = strtotime($this->fields[$idx]);
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
throw new SQLException("Unable to convert value at column " . $column . " to timestamp: " . $this->fields[$idx]);
|
||||
}
|
||||
if ($format === null) {
|
||||
return $ts;
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,289 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: StatementCommon.php,v 1.4 2004/06/13 02:31:07 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that contains common/shared functionality for Statements.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.4 $
|
||||
* @package creole.common
|
||||
*/
|
||||
abstract class StatementCommon {
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
* @var Connection
|
||||
*/
|
||||
protected $conn;
|
||||
|
||||
/**
|
||||
* Temporarily hold a ResultSet object after an execute() query.
|
||||
* @var ResultSet
|
||||
*/
|
||||
protected $resultSet;
|
||||
|
||||
/**
|
||||
* Temporary hold the affected row cound after an execute() query.
|
||||
* @var int
|
||||
*/
|
||||
protected $updateCount;
|
||||
|
||||
/**
|
||||
* Array of warning objects generated by methods performed on result set.
|
||||
* @var array SQLWarning[]
|
||||
*/
|
||||
protected $warnings = array();
|
||||
|
||||
/**
|
||||
* The ResultSet class name.
|
||||
* @var string
|
||||
*/
|
||||
protected $resultClass;
|
||||
|
||||
/**
|
||||
* The prepared statement resource id.
|
||||
* @var resource
|
||||
*/
|
||||
protected $stmt;
|
||||
|
||||
/**
|
||||
* Max rows to retrieve from DB.
|
||||
* @var int
|
||||
*/
|
||||
protected $limit = 0;
|
||||
|
||||
/**
|
||||
* Offset at which to start processing DB rows.
|
||||
* "Skip X rows"
|
||||
* @var int
|
||||
*/
|
||||
protected $offset = 0;
|
||||
|
||||
/**
|
||||
* Create new statement instance.
|
||||
*
|
||||
* @param Connection $conn Connection object
|
||||
*/
|
||||
function __construct(Connection $conn)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of rows to return from db.
|
||||
* This will affect the SQL if the RDBMS supports native LIMIT; if not,
|
||||
* it will be emulated. Limit only applies to queries (not update sql).
|
||||
* @param int $v Maximum number of rows or 0 for all rows.
|
||||
* @return void
|
||||
*/
|
||||
public function setLimit($v)
|
||||
{
|
||||
$this->limit = (int) $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of rows to return or 0 for all.
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit()
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start row.
|
||||
* This will affect the SQL if the RDBMS supports native OFFSET; if not,
|
||||
* it will be emulated. Offset only applies to queries (not update) and
|
||||
* only is evaluated when LIMIT is set!
|
||||
* @param int $v
|
||||
* @return void
|
||||
*/
|
||||
public function setOffset($v)
|
||||
{
|
||||
$this->offset = (int) $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start row.
|
||||
* Offset only applies when Limit is set!
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free resources associated with this statement.
|
||||
* Some drivers will need to implement this method to free
|
||||
* database result resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
// do nothing here (subclasses will implement)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic execute() function has to check to see whether SQL is an update or select query.
|
||||
*
|
||||
* If you already know whether it's a SELECT or an update (manipulating) SQL, then use
|
||||
* the appropriate method, as this one will incurr overhead to check the SQL.
|
||||
*
|
||||
* @param int $fetchmode Fetchmode (only applies to queries).
|
||||
* @return boolean True if it is a result set, false if not or if no more results (this is identical to JDBC return val).
|
||||
* @throws SQLException
|
||||
* @todo -cStatementCommon Update execute() to not use isSelect() method, but rather to determine type based on returned results.
|
||||
*/
|
||||
public function execute($sql, $fetchmode = null)
|
||||
{
|
||||
|
||||
if (!$this->isSelect($sql)) {
|
||||
$this->updateCount = $this->executeUpdate($sql);
|
||||
return false;
|
||||
} else {
|
||||
$this->resultSet = $this->executeQuery($sql, $fetchmode);
|
||||
if ($this->resultSet->getRecordCount() === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get result set.
|
||||
* This assumes that the last thing done was an executeQuery() or an execute()
|
||||
* with SELECT-type query.
|
||||
*
|
||||
* @return RestultSet (or null if none)
|
||||
*/
|
||||
public function getResultSet()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get update count.
|
||||
*
|
||||
* @return int Number of records affected, or <code>null</code> if not applicable.
|
||||
*/
|
||||
public function getUpdateCount()
|
||||
{
|
||||
return $this->updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the passed SQL is a SELECT statement.
|
||||
*
|
||||
* Returns true if SQL starts with 'SELECT' but not 'SELECT INTO'. This exists
|
||||
* to support the execute() function -- which could either execute an update or
|
||||
* a query.
|
||||
*
|
||||
* Currently this function does not take into consideration comments, primarily
|
||||
* because there are a number of different comment options for different drivers:
|
||||
* <pre>
|
||||
* -- SQL-defined comment, but not truly comment in Oracle
|
||||
* # comment in mysql
|
||||
* /* comment in mssql, others * /
|
||||
* // comment sometimes?
|
||||
* REM also comment ...
|
||||
* </pre>
|
||||
*
|
||||
* If you're wondering why we can't just execute the query and look at the return results
|
||||
* to see whether it was an update or a select, the reason is that for update queries we
|
||||
* need to do stuff before we execute them -- like start transactions if auto-commit is off.
|
||||
*
|
||||
* @param string $sql
|
||||
* @return boolean Whether statement is a SELECT SQL statement.
|
||||
* @see execute()
|
||||
*/
|
||||
protected function isSelect($sql)
|
||||
{
|
||||
// is first word is SELECT, then return true, unless it's SELECT INTO ...
|
||||
// this doesn't, however, take comments into account ...
|
||||
$sql = trim($sql);
|
||||
return (stripos($sql, 'select') === 0 && stripos($sql, 'select into ') !== 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the SQL query in this PreparedStatement object and returns the resultset generated by the query.
|
||||
*
|
||||
* @param string $sql This method may optionally be called with the SQL statement.
|
||||
* @param int $fetchmode The mode to use when fetching the results (e.g. ResultSet::FETCHMODE_NUM, ResultSet::FETCHMODE_ASSOC).
|
||||
* @return object Creole::ResultSet
|
||||
* @throws SQLException If there is an error executing the specified query.
|
||||
* @todo -cStatementCommon Put native query execution logic in statement subclasses.
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$this->updateCount = null;
|
||||
if ($this->limit > 0 || $this->offset > 0) {
|
||||
$this->conn->applyLimit($sql, $this->offset, $this->limit);
|
||||
}
|
||||
$this->resultSet = $this->conn->executeQuery($sql, $fetchmode);
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the SQL INSERT, UPDATE, or DELETE statement in this PreparedStatement object.
|
||||
*
|
||||
* @param string $sql This method may optionally be called with the SQL statement.
|
||||
* @return int Number of affected rows (or 0 for drivers that return nothing).
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public function executeUpdate($sql)
|
||||
{
|
||||
if ($this->resultSet) $this->resultSet->close();
|
||||
$this->resultSet = null;
|
||||
$this->updateCount = $this->conn->executeUpdate($sql);
|
||||
return $this->updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets next result set (if this behavior is supported by driver).
|
||||
* Some drivers (e.g. MSSQL) support returning multiple result sets -- e.g.
|
||||
* from stored procedures.
|
||||
*
|
||||
* This function also closes any current restult set.
|
||||
*
|
||||
* Default behavior is for this function to return false. Driver-specific
|
||||
* implementations of this class can override this method if they actually
|
||||
* support multiple result sets.
|
||||
*
|
||||
* @return boolean True if there is another result set, otherwise false.
|
||||
*/
|
||||
public function getMoreResults()
|
||||
{
|
||||
if ($this->resultSet) $this->resultSet->close();
|
||||
$this->resultSet = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the db Connection that created this statement.
|
||||
* @return Connection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->conn;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,268 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Debug implementation of Connection.
|
||||
*
|
||||
* This is a Connection that implements the decorator pattern, wrapping around
|
||||
* the true Connection object (stored in $childConnection). This Connection
|
||||
* tracks information about queries executed and makes that information available
|
||||
* for debugging purposes. The information tracked is the last query executed
|
||||
* on the connection (getLastExecutedQuery()) and the total number of
|
||||
* queries executed on the connection thus far (getNumQueriesExecuted()).
|
||||
*
|
||||
* To use this debug connection, you need to register it as a new Creole
|
||||
* driver that handles all connection types. To do this, call the following
|
||||
* before calling Creole::getConnection():
|
||||
*
|
||||
* <code>
|
||||
* Creole::registerDriver('*', 'creole.drivers.debug.DebugConnection');
|
||||
* </code>
|
||||
*
|
||||
* The next call to Creole::getConnection() will return an instance of
|
||||
* DebugConnection.
|
||||
*
|
||||
* @author Michael Sims
|
||||
* @package creole.drivers.debug
|
||||
*/
|
||||
class DebugConnection implements Connection {
|
||||
|
||||
/** @var Connection */
|
||||
private $childConnection = null;
|
||||
|
||||
/** @var int */
|
||||
private $numQueriesExecuted = 0;
|
||||
|
||||
/** @var string */
|
||||
private $lastExecutedQuery = '';
|
||||
|
||||
/**
|
||||
* @var object Instance of PEAR Log (or other class with log() method).
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Sets a Logger class (e.g. PEAR Log) to use for logging.
|
||||
* The logger class must have a log() method. All messages are logged at default log level.
|
||||
* @param object $logger
|
||||
*/
|
||||
public function setLogger($logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of queries executed on this connection so far
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumQueriesExecuted()
|
||||
{
|
||||
return $this->numQueriesExecuted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last query executed on this connection
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastExecutedQuery()
|
||||
{
|
||||
return $this->lastExecutedQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect()
|
||||
*/
|
||||
public function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
if (!($driver = Creole::getDriver($dsninfo['phptype']))) {
|
||||
throw new SQLException("No driver has been registered to handle connection type: $type");
|
||||
}
|
||||
$connectionClass = Creole::import($driver);
|
||||
$this->childConnection = new $connectionClass();
|
||||
$this->log("connect(): DSN: ". var_export($dsninfo, true) . ", FLAGS: " . var_export($flags, true));
|
||||
return $this->childConnection->connect($dsninfo, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
return $this->childConnection->getDatabaseInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
return $this->childConnection->getIdGenerator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::isConnected()
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return $this->childConnection->isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
$this->log("prepareStatement(): $sql");
|
||||
$obj = $this->childConnection->prepareStatement($sql);
|
||||
$objClass = get_class($obj);
|
||||
return new $objClass($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
$obj = $this->childConnection->createStatement();
|
||||
$objClass = get_class($obj);
|
||||
return new $objClass($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
$this->log("applyLimit(): $sql, offset: $offset, limit: $limit");
|
||||
return $this->childConnection->applyLimit($sql, $offset, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::close()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->log("close(): Closing connection.");
|
||||
return $this->childConnection->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeQuery()
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$this->log("executeQuery(): $sql");
|
||||
$this->lastExecutedQuery = $sql;
|
||||
$this->numQueriesExecuted++;
|
||||
return $this->childConnection->executeQuery($sql, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeUpdate()
|
||||
*/
|
||||
public function executeUpdate($sql)
|
||||
{
|
||||
$this->log("executeUpdate(): $sql");
|
||||
$this->lastExecutedQuery = $sql;
|
||||
$this->numQueriesExecuted++;
|
||||
return $this->childConnection->executeUpdate($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getUpdateCount()
|
||||
*/
|
||||
public function getUpdateCount()
|
||||
{
|
||||
return $this->childConnection->getUpdateCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareCall()
|
||||
**/
|
||||
public function prepareCall($sql)
|
||||
{
|
||||
$this->log("prepareCall(): $sql");
|
||||
return $this->childConnection->prepareCall($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getResource()
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->childConnection->getResource();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::connect()
|
||||
*/
|
||||
public function getDSN()
|
||||
{
|
||||
return $this->childConnection->getDSN();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getFlags()
|
||||
*/
|
||||
public function getFlags()
|
||||
{
|
||||
return $this->childConnection->getFlags();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::begin()
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->log("Beginning transaction.");
|
||||
return $this->childConnection->begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::commit()
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->log("Committing transaction.");
|
||||
return $this->childConnection->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::rollback()
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->log("Rolling back transaction.");
|
||||
return $this->childConnection->rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::setAutoCommit()
|
||||
*/
|
||||
public function setAutoCommit($bit)
|
||||
{
|
||||
$this->log("Setting autocommit to: " . var_export($bit, true));
|
||||
return $this->childConnection->setAutoCommit($bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getAutoCommit()
|
||||
*/
|
||||
public function getAutoCommit()
|
||||
{
|
||||
return $this->childConnection->getAutoCommit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private function that logs message using specified logger (if provided).
|
||||
* @param string $msg Message to log.
|
||||
*/
|
||||
private function log($msg)
|
||||
{
|
||||
if ($this->logger) {
|
||||
$this->logger->log($msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,478 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MSSQLCallableStatement.php,v 1.20 2005/09/16 13:09: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/drivers/mssql/MSSQLPreparedStatement.php';
|
||||
require_once 'creole/CallableStatement.php';
|
||||
include_once 'creole/CreoleTypes.php';
|
||||
|
||||
/**
|
||||
* MS SQL Server class to handle stored procedure execution.
|
||||
*
|
||||
* Developer note:
|
||||
*
|
||||
* There is no CallableStatement superclass. Unlike JDBC, Creole
|
||||
* uses abstract parent classes rather than interfaces -- in order
|
||||
* to minimize code duplication. Since PHP doesn't support multiple
|
||||
* inheritance, the DRIVERCallableStatement class cannot extend both
|
||||
* the DRIVERPreparedStatement class and the would-be abstract
|
||||
* CallableStatement class.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.20 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLCallableStatement extends MSSQLPreparedStatement implements CallableStatement {
|
||||
|
||||
/** Output variables */
|
||||
private $boundOutVars = array();
|
||||
|
||||
/**
|
||||
* Match Creole types to SQL Server types
|
||||
* @var array
|
||||
*/
|
||||
private static $typeMap = array(
|
||||
CreoleTypes::BOOLEAN => SQLBIT,
|
||||
CreoleTypes::BIGINT => SQLINT4,
|
||||
CreoleTypes::SMALLINT => SQLINT2,
|
||||
CreoleTypes::TINYINT => SQLINT2,
|
||||
CreoleTypes::INTEGER => SQLINT4,
|
||||
CreoleTypes::CHAR => SQLCHAR,
|
||||
CreoleTypes::VARCHAR => SQLVARCHAR,
|
||||
CreoleTypes::TEXT => SQLTEXT,
|
||||
CreoleTypes::FLOAT => SQLFLT8,
|
||||
CreoleTypes::DOUBLE => SQLFLT8,
|
||||
CreoleTypes::DATE => SQLVARCHAR,
|
||||
CreoleTypes::TIME => SQLVARCHAR,
|
||||
CreoleTypes::TIMESTAMP => SQLVARCHAR,
|
||||
CreoleTypes::VARBINARY => SQLVARCHAR,
|
||||
CreoleTypes::NUMERIC => SQLINT4,
|
||||
CreoleTypes::DECIMAL => SQLFLT8
|
||||
);
|
||||
|
||||
/**
|
||||
* Statement created by mssql_init()
|
||||
* @var resource
|
||||
*/
|
||||
private $stmt;
|
||||
|
||||
|
||||
/**
|
||||
* The result resource.
|
||||
* @var resource
|
||||
*/
|
||||
private $result;
|
||||
|
||||
/**
|
||||
* Construct new MSSQLCallableStatement.
|
||||
*
|
||||
* @param Connection $conn
|
||||
* @param resource $stmt
|
||||
*/
|
||||
public function __construct(Connection $conn, $stmt)
|
||||
{
|
||||
print " - > IN CONSTRUCTOR \n";
|
||||
$this->conn = $conn;
|
||||
$this->stmt = $stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getResource()
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
@mssql_free_statement($this->stmt);
|
||||
$this->rsFetchCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::executeQuery()
|
||||
*/
|
||||
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->result = mssql_execute($this->stmt);
|
||||
if (!$this->result) {
|
||||
throw new SQLException('unable to execute callable statement', mssql_get_last_message());
|
||||
}
|
||||
|
||||
return new MSSQLResultSet($this->conn, $this->result, $fetchmode, $this->offset, $this->limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getMoreResults()
|
||||
*/
|
||||
function getMoreResults()
|
||||
{
|
||||
$this->rsFetchCount++; // we track this because
|
||||
$hasMore = mssql_next_result($this->result);
|
||||
if ($this->resultSet) $this->resultSet->close();
|
||||
if ($hasMore) {
|
||||
$clazz = $this->resultClass;
|
||||
$this->resultSet = new $clazz($this, $this->result);
|
||||
} else {
|
||||
$this->resultSet = null;
|
||||
}
|
||||
return $hasMore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::registerOutParameter()
|
||||
*/
|
||||
function registerOutParameter($paramIndex, $sqlType, $maxLength = null)
|
||||
{
|
||||
mssql_bind($this->stmt, $paramIndex, $this->boundOutVars[$paramIndex], self::$typeMap[$sqlType], true, false, $maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setArray()
|
||||
*/
|
||||
function setArray($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$value = serialize($value);
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLTEXT, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setBoolean()
|
||||
*/
|
||||
function setBoolean($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$value = ($value) ? 1 : 0;
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLBIT, $out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setBlob()
|
||||
*/
|
||||
function setBlob($paramIndex, $blob, $out = false)
|
||||
{
|
||||
if ($blob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if (is_object($blob)) {
|
||||
$blob = $blob->__toString();
|
||||
}
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$blob; // reference means that changes to value, will be reflected
|
||||
$data = unpack("H*hex", $blob);
|
||||
mssql_bind($this->stmt, $paramIndex, $data, SQLTEXT, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setClob()
|
||||
*/
|
||||
function setClob($paramIndex, $clob, $out = false)
|
||||
{
|
||||
if ($clob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if (is_object($clob)) {
|
||||
$clob = $clob->__toString();
|
||||
}
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$clob; // reference means that changes to value, will be reflected
|
||||
mssql_bind($this->stmt, $paramIndex, $clob, SQLTEXT, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setDate()
|
||||
*/
|
||||
function setDate($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if (is_numeric($value)) $value = date("Y-m-d", $value);
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLVARCHAR, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setFloat()
|
||||
*/
|
||||
function setFloat($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$value = (float) $value;
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLFLT8, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setInt()
|
||||
*/
|
||||
function setInt($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$value = (int) $value;
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLINT4, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setNull()
|
||||
*/
|
||||
function setNull($paramIndex)
|
||||
{
|
||||
// hopefully type isn't essential here :)
|
||||
$value = null; // wants a var to pass by reference
|
||||
mssql_bind($this->stmt, $paramIndex, $value, $type=null, $out=false, $is_null=true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setString()
|
||||
*/
|
||||
function setString($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
$value = (string) $value;
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLVARCHAR, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setTime()
|
||||
*/
|
||||
function setTime($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if (is_numeric($value)) $value = date("H:i:s", $value);
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLVARCHAR, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::setTimestamp()
|
||||
*/
|
||||
function setTimestamp($paramIndex, $value, $out = false)
|
||||
{
|
||||
if ($out) $this->boundOutVars[$paramIndex] = &$value; // reference means that changes to value, will be reflected
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if (is_numeric($value)) $value = date('Y-m-d H:i:s', $value);
|
||||
mssql_bind($this->stmt, $paramIndex, $value, SQLVARCHAR, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getArray()
|
||||
*/
|
||||
function getArray($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
return (array) unserialize($this->boundOutVars[$paramIndex]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getBoolean()
|
||||
*/
|
||||
function getBoolean($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
return (boolean) $this->boundOutVars[$paramIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getBlob()
|
||||
*/
|
||||
function getBlob($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
require_once 'creole/util/Blob.php';
|
||||
$b = new Blob();
|
||||
$b->setContents($this->boundOutVars[$paramIndex]);
|
||||
return $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getClob()
|
||||
*/
|
||||
function getClob($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
require_once 'creole/util/Clob.php';
|
||||
$c = new Clob();
|
||||
$c->setContents($this->boundOutVars[$paramIndex]);
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getDate()
|
||||
*/
|
||||
function getDate($paramIndex, $fmt = '%Y-%m-%d')
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
|
||||
$ts = strtotime($this->boundOutVars[$paramIndex]);
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
throw new SQLException("Unable to convert value at column " . $paramIndex . " to timestamp: " . $this->boundOutVars[$paramIndex]);
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
|
||||
return $this->boundOutVars[$paramIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $paramIndex Column name (string) or index (int).
|
||||
* @return float
|
||||
*/
|
||||
function getFloat($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
return (float) $this->boundOutVars[$paramIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getInt()
|
||||
*/
|
||||
function getInt($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
return (int) $this->boundOutVars[$paramIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getString()
|
||||
*/
|
||||
function getString($paramIndex)
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
return (string) $this->boundOutVars[$paramIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getTime()
|
||||
*/
|
||||
function getTime($paramIndex, $format='%X')
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
|
||||
$ts = strtotime($this->boundOutVars[$paramIndex]);
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
throw new SQLException("Unable to convert value at column " . $paramIndex . " to timestamp: " . $this->boundOutVars[$paramIndex]);
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CallableStatement::getTimestamp()
|
||||
*/
|
||||
function getTimestamp($paramIndex, $format = 'Y-m-d H:i:s')
|
||||
{
|
||||
if (!array_key_exists($paramIndex, $this->boundOutVars)) {
|
||||
throw new SQLException('Requesting variable not bound to output var: '.$paramIndex);
|
||||
}
|
||||
if ($this->boundOutVars[$paramIndex] === null) { return null; }
|
||||
|
||||
$ts = strtotime($this->boundOutVars[$paramIndex]);
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
throw new SQLException("Unable to convert value at column " . $paramIndex . " to timestamp: " . $this->boundOutVars[$paramIndex]);
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: MSSQLConnection.php,v 1.25 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/mssql/MSSQLResultSet.php';
|
||||
|
||||
/**
|
||||
* MS SQL Server implementation of Connection.
|
||||
*
|
||||
* If you have trouble with BLOB / CLOB support
|
||||
* --------------------------------------------
|
||||
*
|
||||
* You may need to change some PHP ini settings. In particular, the following settings
|
||||
* set the text size to maximum which should get around issues with truncated data:
|
||||
* <code>
|
||||
* ini_set('mssql.textsize', 2147483647);
|
||||
* ini_set('mssql.textlimit', 2147483647);
|
||||
* </code>
|
||||
* We do not set these by default (anymore) because they do not apply to cases where MSSQL
|
||||
* is being used w/ FreeTDS.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @author Stig Bakken <ssb@fast.no>
|
||||
* @author Lukas Smith
|
||||
* @version $Revision: 1.25 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLConnection extends ConnectionCommon implements Connection {
|
||||
|
||||
/** Current database (used in mssql_select_db()). */
|
||||
private $database;
|
||||
|
||||
/**
|
||||
* @see Connection::connect()
|
||||
*/
|
||||
function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
if (!extension_loaded('mssql') && !extension_loaded('sybase') && !extension_loaded('sybase_ct')) {
|
||||
throw new SQLException('mssql extension not loaded');
|
||||
}
|
||||
|
||||
$this->dsn = $dsninfo;
|
||||
$this->flags = $flags;
|
||||
|
||||
$persistent = ($flags & Creole::PERSISTENT === Creole::PERSISTENT);
|
||||
|
||||
$user = $dsninfo['username'];
|
||||
$pw = $dsninfo['password'];
|
||||
$dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
|
||||
|
||||
if (PHP_OS == "WINNT" || PHP_OS == "WIN32") {
|
||||
$portDelimiter = ",";
|
||||
} else {
|
||||
$portDelimiter = ":";
|
||||
}
|
||||
|
||||
if(!empty($dsninfo['port'])) {
|
||||
$dbhost .= $portDelimiter.$dsninfo['port'];
|
||||
} else {
|
||||
$dbhost .= $portDelimiter.'1433';
|
||||
}
|
||||
|
||||
$connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
|
||||
|
||||
if ($dbhost && $user && $pw) {
|
||||
$conn = @$connect_function($dbhost, $user, $pw);
|
||||
} elseif ($dbhost && $user) {
|
||||
$conn = @$connect_function($dbhost, $user);
|
||||
} else {
|
||||
$conn = @$connect_function($dbhost);
|
||||
}
|
||||
if (!$conn) {
|
||||
throw new SQLException('connect failed', mssql_get_last_message());
|
||||
}
|
||||
|
||||
if ($dsninfo['database']) {
|
||||
if (!@mssql_select_db($dsninfo['database'], $conn)) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$this->database = $dsninfo['database'];
|
||||
}
|
||||
|
||||
$this->dblink = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
require_once 'creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php';
|
||||
return new MSSQLDatabaseInfo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
require_once 'creole/drivers/mssql/MSSQLIdGenerator.php';
|
||||
return new MSSQLIdGenerator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
require_once 'creole/drivers/mssql/MSSQLPreparedStatement.php';
|
||||
return new MSSQLPreparedStatement($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
require_once 'creole/drivers/mssql/MSSQLStatement.php';
|
||||
return new MSSQLStatement($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false since MSSQL doesn't support this method.
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
$ret = @mssql_close($this->dblink);
|
||||
$this->dblink = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeQuery()
|
||||
*/
|
||||
function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$this->lastQuery = $sql;
|
||||
if (!@mssql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
$result = @mssql_query($sql, $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute query', mssql_get_last_message());
|
||||
}
|
||||
return new MSSQLResultSet($this, $result, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeUpdate()
|
||||
*/
|
||||
function executeUpdate($sql)
|
||||
{
|
||||
|
||||
$this->lastQuery = $sql;
|
||||
if (!mssql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$result = @mssql_query($sql, $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute update', mssql_get_last_message(), $sql);
|
||||
}
|
||||
|
||||
return $this->getUpdateCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
$result = @mssql_query('BEGIN TRAN', $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not begin transaction', mssql_get_last_message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
if (!@mssql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
$result = @mssql_query('COMMIT TRAN', $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not commit transaction', mssql_get_last_message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
if (!@mssql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('no database selected');
|
||||
}
|
||||
$result = @mssql_query('ROLLBACK TRAN', $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not rollback transaction', mssql_get_last_message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of rows affected by the last query.
|
||||
* if the last query was a select, returns 0.
|
||||
*
|
||||
* @return int Number of rows affected by the last query
|
||||
* @throws SQLException
|
||||
*/
|
||||
function getUpdateCount()
|
||||
{
|
||||
$res = @mssql_query('select @@rowcount', $this->dblink);
|
||||
if (!$res) {
|
||||
throw new SQLException('Unable to get affected row count', mssql_get_last_message());
|
||||
}
|
||||
$ar = @mssql_fetch_row($res);
|
||||
if (!$ar) {
|
||||
$result = 0;
|
||||
} else {
|
||||
@mssql_free_result($res);
|
||||
$result = $ar[0];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a CallableStatement object for calling database stored procedures.
|
||||
*
|
||||
* @param string $sql
|
||||
* @return CallableStatement
|
||||
* @throws SQLException
|
||||
*/
|
||||
function prepareCall($sql)
|
||||
{
|
||||
require_once 'creole/drivers/mssql/MSSQLCallableStatement.php';
|
||||
$stmt = mssql_init($sql);
|
||||
if (!$stmt) {
|
||||
throw new SQLException('Unable to prepare statement', mssql_get_last_message(), $sql);
|
||||
}
|
||||
return new MSSQLCallableStatement($this, $stmt);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once 'creole/IdGenerator.php';
|
||||
|
||||
/**
|
||||
* MSSQL IdGenerator implimenation.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.6 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLIdGenerator 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 false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::isAfterInsert()
|
||||
*/
|
||||
public function isAfterInsert()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::getIdMethod()
|
||||
*/
|
||||
public function getIdMethod()
|
||||
{
|
||||
return self::AUTOINCREMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::getId()
|
||||
*/
|
||||
public function getId($unused = null)
|
||||
{
|
||||
$rs = $this->conn->executeQuery("SELECT SCOPE_IDENTITY()", ResultSet::FETCHMODE_NUM);
|
||||
$rs->next();
|
||||
return $rs->getInt(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MSSQLPreparedStatement.php,v 1.13 2005/11/13 01:29:01 gamr 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';
|
||||
|
||||
/**
|
||||
* MSSQL specific PreparedStatement functions.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.13 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLPreparedStatement extends PreparedStatementCommon implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* MSSQL-specific implementation of setBlob().
|
||||
*
|
||||
* If you are having trouble getting BLOB data into the database, see the phpdoc comment
|
||||
* in the MSSQLConnection for some PHP ini values that may need to be set. (This also
|
||||
* applies to CLOB support.)
|
||||
*
|
||||
* @param int $paramIndex
|
||||
* @param mixed $value Blob object or string.
|
||||
* @return void
|
||||
*/
|
||||
function setBlob($paramIndex, $blob)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
if ($blob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
// they took magic __toString() out of PHP5.0.0; this sucks
|
||||
if (is_object($blob)) {
|
||||
$blob = $blob->__toString();
|
||||
}
|
||||
$data = unpack("H*hex", $blob);
|
||||
$this->boundInVars[$paramIndex] = '0x'.$data['hex']; // no surrounding quotes!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add quotes using str_replace.
|
||||
* This is not as thorough as MySQL.
|
||||
*/
|
||||
protected function escape($subject)
|
||||
{
|
||||
// use this instead of magic_quotes_sybase + addslashes(),
|
||||
// just in case multiple RDBMS being used at the same time
|
||||
return str_replace("'", "''", $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* MSSQL must emulate OFFSET/LIMIT support.
|
||||
*/
|
||||
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->replaceParams();
|
||||
|
||||
$this->resultSet = $this->conn->executeQuery($sql, $fetchmode);
|
||||
$this->resultSet->_setOffset($this->offset);
|
||||
$this->resultSet->_setLimit($this->limit);
|
||||
return $this->resultSet;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MSSQLResultSet.php,v 1.21 2006/01/17 19:44:38 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';
|
||||
|
||||
/**
|
||||
* MSSQL implementation of ResultSet.
|
||||
*
|
||||
* MS SQL does not support LIMIT or OFFSET natively so the methods
|
||||
* in here need to perform some adjustments and extra checking to make sure
|
||||
* that this behaves the same as RDBMS drivers using native OFFSET/LIMIT.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.21 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLResultSet extends ResultSetCommon implements ResultSet {
|
||||
|
||||
/**
|
||||
* Offset at which to start reading rows.
|
||||
* @var int
|
||||
*/
|
||||
private $offset = 0;
|
||||
|
||||
/**
|
||||
* Maximum rows to retrieve, or 0 if all.
|
||||
* @var int
|
||||
*/
|
||||
private $limit = 0;
|
||||
|
||||
/**
|
||||
* This MSSQL-only function exists to set offset after ResultSet is instantiated.
|
||||
* This function should be "protected" in Java sense: only available to classes in package.
|
||||
* THIS METHOD SHOULD NOT BE CALLED BY ANYTHING EXCEPTION DRIVER CLASSES.
|
||||
* @param int $offset New offset. If great than 0, then seek(0) will be called to move cursor.
|
||||
* @access protected
|
||||
*/
|
||||
public function _setOffset($offset)
|
||||
{
|
||||
$this->offset = $offset;
|
||||
if ($offset > 0) {
|
||||
$this->seek(0); // 0 becomes $offset by seek() method
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This MSSQL-only function exists to set limit after ResultSet is instantiated.
|
||||
* This function should be "protected" in Java sense: only available to classes in package.
|
||||
* THIS METHOD SHOULD NOT BE CALLED BY ANYTHING EXCEPTION DRIVER CLASSES.
|
||||
* @param int $limit New limit.
|
||||
* @access protected
|
||||
*/
|
||||
public function _setLimit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
function seek($rownum)
|
||||
{
|
||||
// support emulated OFFSET
|
||||
$actual = $rownum + $this->offset;
|
||||
|
||||
if (($this->limit > 0 && $rownum >= $this->limit) || $rownum < 0) {
|
||||
// have to check for rownum < 0, because mssql_seek() won't
|
||||
// complain if the $actual is valid.
|
||||
return false;
|
||||
}
|
||||
|
||||
// MSSQL rows start w/ 0, but this works, because we are
|
||||
// looking to move the position _before_ the next desired position
|
||||
if (!@mssql_data_seek($this->result, $actual)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cursorPos = $rownum;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
// support emulated LIMIT
|
||||
if ( $this->limit > 0 && ($this->cursorPos >= $this->limit) ) {
|
||||
$this->afterLast();
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->fields = mssql_fetch_array($this->result, $this->fetchmode);
|
||||
|
||||
if (!$this->fields) {
|
||||
if ($errmsg = mssql_get_last_message()) {
|
||||
throw new SQLException("Error fetching result", $errmsg);
|
||||
} else {
|
||||
// We've advanced beyond end of recordset.
|
||||
$this->afterLast();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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 = @mssql_num_rows($this->result);
|
||||
if ($rows === null) {
|
||||
throw new SQLException('Error getting record count', mssql_get_last_message());
|
||||
}
|
||||
// adjust count based on emulated LIMIT/OFFSET
|
||||
$rows -= $this->offset;
|
||||
return ($this->limit > 0 && $rows > $this->limit ? $this->limit : $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
$ret = @mssql_free_result($this->result);
|
||||
$this->result = false;
|
||||
$this->fields = array();
|
||||
$this->limit = 0;
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MSSQLStatement.php,v 1.4 2004/06/13 02:31:07 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/common/StatementCommon.php';
|
||||
require_once 'creole/Statement.php';
|
||||
|
||||
/**
|
||||
* Class that contains MSSQL functionality for Statements.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.4 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLStatement extends StatementCommon implements Statement {
|
||||
|
||||
/**
|
||||
* Executes the SQL query in this PreparedStatement object and returns the resultset generated by the query.
|
||||
*
|
||||
* @param string $sql This method may optionally be called with the SQL statement.
|
||||
* @param int $fetchmode The mode to use when fetching the results (e.g. ResultSet::FETCHMODE_NUM, ResultSet::FETCHMODE_ASSOC).
|
||||
* @return object Creole::ResultSet
|
||||
* @throws SQLException If there is an error executing the specified query.
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$this->updateCount = null;
|
||||
$this->resultSet = $this->conn->executeQuery($sql, $fetchmode);
|
||||
$this->resultSet->_setOffset($this->offset);
|
||||
$this->resultSet->_setLimit($this->limit);
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets next result set (if this behavior is supported by driver).
|
||||
* Some drivers (e.g. MSSQL) support returning multiple result sets -- e.g.
|
||||
* from stored procedures.
|
||||
*
|
||||
* This function also closes any current restult set.
|
||||
*
|
||||
* Default behavior is for this function to return false. Driver-specific
|
||||
* implementations of this class can override this method if they actually
|
||||
* support multiple result sets.
|
||||
*
|
||||
* @return boolean True if there is another result set, otherwise false.
|
||||
*/
|
||||
public function getMoreResults()
|
||||
{
|
||||
if ($this->resultSet) $this->resultSet->close();
|
||||
$this->resultSet = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: MSSQLTypes.php,v 1.8 2004/07/27 23: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';
|
||||
|
||||
/**
|
||||
* MSSQL types / type map.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.8 $
|
||||
* @package creole.drivers.mssql
|
||||
*/
|
||||
class MSSQLTypes extends CreoleTypes {
|
||||
|
||||
/** Map PostgreSQL native types to Creole (JDBC) types. */
|
||||
private static $typeMap = array (
|
||||
"binary" => CreoleTypes::BINARY,
|
||||
"bit" => CreoleTypes::BOOLEAN,
|
||||
"char" => CreoleTypes::CHAR,
|
||||
"datetime" => CreoleTypes::TIMESTAMP,
|
||||
"decimal() identity" => CreoleTypes::DECIMAL,
|
||||
"decimal" => CreoleTypes::DECIMAL,
|
||||
"image" => CreoleTypes::LONGVARBINARY,
|
||||
"int" => CreoleTypes::INTEGER,
|
||||
"int identity" => CreoleTypes::INTEGER,
|
||||
"integer" => CreoleTypes::INTEGER,
|
||||
"money" => CreoleTypes::DECIMAL,
|
||||
"nchar" => CreoleTypes::CHAR,
|
||||
"ntext" => CreoleTypes::LONGVARCHAR,
|
||||
"numeric() identity" => CreoleTypes::NUMERIC,
|
||||
"numeric" => CreoleTypes::NUMERIC,
|
||||
"nvarchar" => CreoleTypes::VARCHAR,
|
||||
"real" => CreoleTypes::REAL,
|
||||
"float" => CreoleTypes::FLOAT,
|
||||
"smalldatetime" => CreoleTypes::TIMESTAMP,
|
||||
"smallint" => CreoleTypes::SMALLINT,
|
||||
"smallint identity" => CreoleTypes::SMALLINT,
|
||||
"smallmoney" => CreoleTypes::DECIMAL,
|
||||
"sysname" => CreoleTypes::VARCHAR,
|
||||
"text" => CreoleTypes::LONGVARCHAR,
|
||||
"timestamp" => CreoleTypes::BINARY,
|
||||
"tinyint identity" => CreoleTypes::TINYINT,
|
||||
"tinyint" => CreoleTypes::TINYINT,
|
||||
"uniqueidentifier" => CreoleTypes::CHAR,
|
||||
"varbinary" => CreoleTypes::VARBINARY,
|
||||
"varchar" => CreoleTypes::VARCHAR,
|
||||
"uniqueidentifier" => CreoleTypes::CHAR,
|
||||
// SQL Server 2000 only
|
||||
"bigint identity" => CreoleTypes::BIGINT,
|
||||
"bigint" => CreoleTypes::BIGINT,
|
||||
"sql_variant" => CreoleTypes::VARCHAR,
|
||||
);
|
||||
|
||||
/** Reverse lookup map, created on demand. */
|
||||
private static $reverseMap = null;
|
||||
|
||||
public static function getType($mssqlType)
|
||||
{
|
||||
$t = strtolower($mssqlType);
|
||||
if (isset(self::$typeMap[$t])) {
|
||||
return self::$typeMap[$t];
|
||||
} else {
|
||||
return CreoleTypes::OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getNativeType($creoleType)
|
||||
{
|
||||
if (self::$reverseMap === null) {
|
||||
self::$reverseMap = array_flip(self::$typeMap);
|
||||
}
|
||||
return @self::$reverseMap[$creoleType];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MSSQLDatabaseInfo.php,v 1.11 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* MSSQL impementation of DatabaseInfo.
|
||||
*
|
||||
* @author Hans Lellelid
|
||||
* @version $Revision: 1.11 $
|
||||
* @package creole.drivers.mssql.metadata
|
||||
*/
|
||||
class MSSQLDatabaseInfo extends DatabaseInfo {
|
||||
|
||||
/**
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function initTables()
|
||||
{
|
||||
include_once 'creole/drivers/mssql/metadata/MSSQLTableInfo.php';
|
||||
|
||||
$dsn = $this->conn->getDSN();
|
||||
|
||||
|
||||
if (!@mssql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$result = mssql_query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'", $this->conn->getResource());
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list tables", mssql_get_last_message());
|
||||
}
|
||||
|
||||
while ($row = mssql_fetch_row($result)) {
|
||||
$this->tables[strtoupper($row[0])] = new MSSQLTableInfo($this, $row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function initSequences()
|
||||
{
|
||||
// there are no sequences -- afaik -- in MSSQL.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MSSQLTableInfo.php,v 1.14 2006/01/17 19:44:39 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';
|
||||
require_once 'creole/metadata/TableInfo.php';
|
||||
|
||||
/**
|
||||
* MSSQL implementation of TableInfo.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.14 $
|
||||
* @package creole.drivers.mssql.metadata
|
||||
*/
|
||||
class MSSQLTableInfo extends TableInfo {
|
||||
|
||||
/**
|
||||
* Loads the columns for this table.
|
||||
* @return void
|
||||
*/
|
||||
protected function initColumns()
|
||||
{
|
||||
include_once 'creole/metadata/ColumnInfo.php';
|
||||
include_once 'creole/drivers/mssql/MSSQLTypes.php';
|
||||
|
||||
if (!@mssql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$res = mssql_query("sp_columns ".$this->name, $this->conn->getResource());
|
||||
if (!$res) {
|
||||
throw new SQLException('Could not get column names', mssql_get_last_message());
|
||||
}
|
||||
|
||||
while ($row = mssql_fetch_array($res)) {
|
||||
$name = $row['COLUMN_NAME'];
|
||||
$type = $row['TYPE_NAME'];
|
||||
$length = $row['LENGTH'];
|
||||
$is_nullable = $row['NULLABLE'];
|
||||
$default = $row['COLUMN_DEF'];
|
||||
$precision = $row['PRECISION'];
|
||||
$scale = $row['SCALE'];
|
||||
$identity = false;
|
||||
if (strtolower($type) == "int identity") {
|
||||
$identity = true;
|
||||
}
|
||||
$this->columns[$name] = new ColumnInfo($this, $name, MSSQLTypes::getType($type), $type, $length, $precision, $scale, $is_nullable, $default, $identity);
|
||||
}
|
||||
|
||||
$this->colsLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the indexes for this table.
|
||||
* @return void
|
||||
*/
|
||||
protected function initIndexes()
|
||||
{
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
include_once 'creole/metadata/IndexInfo.php';
|
||||
|
||||
if (!@mssql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$res = mssql_query("sp_indexes_rowset ".$this->name, $this->conn->getResource());
|
||||
|
||||
while ($row = mssql_fetch_array($res)) {
|
||||
$name = $row['INDEX_NAME'];
|
||||
// All primary keys are indexes (right...?)
|
||||
if (!isset($this->indexes[$name])) {
|
||||
$this->indexes[$name] = new IndexInfo($name);
|
||||
}
|
||||
$this->indexes[$name]->addColumn($this->columns[ $row['COLUMN_NAME'] ]);
|
||||
}
|
||||
|
||||
$this->indexesLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the foreign keys for this table.
|
||||
* @return void
|
||||
*/
|
||||
protected function initForeignKeys()
|
||||
{
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
include_once 'creole/metadata/ForeignKeyInfo.php';
|
||||
|
||||
if (!@mssql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$res = mssql_query("SELECT ccu1.TABLE_NAME, ccu1.COLUMN_NAME, ccu2.TABLE_NAME AS FK_TABLE_NAME, ccu2.COLUMN_NAME AS FK_COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu1 INNER JOIN
|
||||
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc1 ON tc1.CONSTRAINT_NAME = ccu1.CONSTRAINT_NAME AND
|
||||
CONSTRAINT_TYPE = 'Foreign Key' INNER JOIN
|
||||
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1 ON rc1.CONSTRAINT_NAME = tc1.CONSTRAINT_NAME INNER JOIN
|
||||
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu2 ON ccu2.CONSTRAINT_NAME = rc1.UNIQUE_CONSTRAINT_NAME
|
||||
WHERE (ccu1.table_name = '".$this->name."')", $this->conn->getResource());
|
||||
|
||||
while($row = mssql_fetch_array($res)) {
|
||||
$name = $row['COLUMN_NAME'];
|
||||
$ftbl = $row['FK_TABLE_NAME'];
|
||||
$fcol = $row['FK_COLUMN_NAME'];
|
||||
|
||||
if (!isset($this->foreignKeys[$name])) {
|
||||
$this->foreignKeys[$name] = new ForeignKeyInfo($name);
|
||||
|
||||
if ($this->database->hasTable($ftbl)) {
|
||||
$foreignTable = $this->database->getTable($ftbl);
|
||||
} else {
|
||||
$foreignTable = new TableInfo($ltbl);
|
||||
$this->database->addTable($foreignTable);
|
||||
}
|
||||
|
||||
if ($foreignTable->hasColumn($fcol)) {
|
||||
$foreignCol = $foreignTable->getColumn($fcol);
|
||||
} else {
|
||||
$foreignCol = new ColumnInfo($foreignTable, $fcol);
|
||||
$foreignTable->addColumn($foreignCol);
|
||||
}
|
||||
|
||||
$this->foreignKeys[$name]->addReference($this->columns[$name], $foreignCol);
|
||||
}
|
||||
}
|
||||
|
||||
$this->fksLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the primary key info for this table.
|
||||
* @return void
|
||||
*/
|
||||
protected function initPrimaryKey()
|
||||
{
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
include_once 'creole/metadata/PrimaryKeyInfo.php';
|
||||
|
||||
if (!@mssql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
$res = mssql_query("SELECT COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
|
||||
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ON
|
||||
INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_NAME = INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE.constraint_name
|
||||
WHERE (INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'PRIMARY KEY') AND
|
||||
(INFORMATION_SCHEMA.TABLE_CONSTRAINTS.TABLE_NAME = '".$this->name."')", $this->conn->getResource());
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together.
|
||||
// name of the primary key will be the first column name in the key.
|
||||
while($row = mssql_fetch_row($res)) {
|
||||
$name = $row[0];
|
||||
if (!isset($this->primaryKey)) {
|
||||
$this->primaryKey = new PrimaryKeyInfo($name);
|
||||
}
|
||||
$this->primaryKey->addColumn($this->columns[ $name ]);
|
||||
}
|
||||
|
||||
$this->pkLoaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLConnection.php,v 1.18 2004/09/01 14:00:28 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/mysql/MySQLResultSet.php';
|
||||
|
||||
/**
|
||||
* MySQL implementation of Connection.
|
||||
*
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @author Stig Bakken <ssb@fast.no>
|
||||
* @author Lukas Smith
|
||||
* @version $Revision: 1.18 $
|
||||
* @package creole.drivers.mysql
|
||||
*/
|
||||
class MySQLConnection extends ConnectionCommon implements Connection {
|
||||
|
||||
/** Current database (used in mysql_select_db()). */
|
||||
private $database;
|
||||
|
||||
/**
|
||||
* Connect to a database and log in as the specified user.
|
||||
*
|
||||
* @param $dsn the data source name (see DB::parseDSN for syntax)
|
||||
* @param $flags Any conneciton flags.
|
||||
* @access public
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
if (!extension_loaded('mysql')) {
|
||||
throw new SQLException('mysql extension not loaded');
|
||||
}
|
||||
|
||||
$this->dsn = $dsninfo;
|
||||
$this->flags = $flags;
|
||||
|
||||
$persistent = ($flags & Creole::PERSISTENT) === Creole::PERSISTENT;
|
||||
|
||||
if (isset($dsninfo['protocol']) && $dsninfo['protocol'] == 'unix') {
|
||||
$dbhost = ':' . $dsninfo['socket'];
|
||||
} else {
|
||||
$dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
|
||||
if (!empty($dsninfo['port'])) {
|
||||
$dbhost .= ':' . $dsninfo['port'];
|
||||
}
|
||||
}
|
||||
$user = $dsninfo['username'];
|
||||
$pw = $dsninfo['password'];
|
||||
|
||||
$encoding = !empty($dsninfo['encoding']) ? $dsninfo['encoding'] : null;
|
||||
|
||||
$connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';
|
||||
|
||||
@ini_set('track_errors', true);
|
||||
if ($dbhost && $user && $pw) {
|
||||
$conn = @$connect_function($dbhost, $user, $pw);
|
||||
} elseif ($dbhost && $user) {
|
||||
$conn = @$connect_function($dbhost, $user);
|
||||
} elseif ($dbhost) {
|
||||
$conn = @$connect_function($dbhost);
|
||||
} else {
|
||||
$conn = false;
|
||||
}
|
||||
@ini_restore('track_errors');
|
||||
if (empty($conn)) {
|
||||
if (($err = @mysql_error()) != '') {
|
||||
throw new SQLException("connect failed", $err);
|
||||
} elseif (empty($php_errormsg)) {
|
||||
throw new SQLException("connect failed");
|
||||
} else {
|
||||
throw new SQLException("connect failed", $php_errormsg);
|
||||
}
|
||||
}
|
||||
|
||||
if ($dsninfo['database']) {
|
||||
if (!@mysql_select_db($dsninfo['database'], $conn)) {
|
||||
switch(mysql_errno($conn)) {
|
||||
case 1049:
|
||||
$exc = new SQLException("no such database", mysql_error($conn));
|
||||
break;
|
||||
case 1044:
|
||||
$exc = new SQLException("access violation", mysql_error($conn));
|
||||
break;
|
||||
default:
|
||||
$exc = new SQLException("cannot select database", mysql_error($conn));
|
||||
}
|
||||
|
||||
throw $exc;
|
||||
|
||||
}
|
||||
// fix to allow calls to different databases in the same script
|
||||
$this->database = $dsninfo['database'];
|
||||
}
|
||||
|
||||
$this->dblink = $conn;
|
||||
|
||||
if ($encoding) {
|
||||
$this->executeUpdate("SET NAMES " . $encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
require_once 'creole/drivers/mysql/metadata/MySQLDatabaseInfo.php';
|
||||
return new MySQLDatabaseInfo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
require_once 'creole/drivers/mysql/MySQLIdGenerator.php';
|
||||
return new MySQLIdGenerator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
require_once 'creole/drivers/mysql/MySQLPreparedStatement.php';
|
||||
return new MySQLPreparedStatement($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareCall()
|
||||
*/
|
||||
public function prepareCall($sql) {
|
||||
throw new SQLException('MySQL does not support stored procedures.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
require_once 'creole/drivers/mysql/MySQLStatement.php';
|
||||
return new MySQLStatement($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::disconnect()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
$ret = mysql_close($this->dblink);
|
||||
$this->dblink = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ( $limit > 0 ) {
|
||||
$sql .= " LIMIT " . ($offset > 0 ? $offset . ", " : "") . $limit;
|
||||
} else if ( $offset > 0 ) {
|
||||
$sql .= " LIMIT " . $offset . ", 18446744073709551615";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeQuery()
|
||||
*/
|
||||
function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$this->lastQuery = $sql;
|
||||
if ($this->database) {
|
||||
if (!@mysql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
$result = @mysql_query($sql, $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute query', mysql_error($this->dblink), $sql);
|
||||
}
|
||||
return new MySQLResultSet($this, $result, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeUpdate()
|
||||
*/
|
||||
function executeUpdate($sql)
|
||||
{
|
||||
$this->lastQuery = $sql;
|
||||
|
||||
if ($this->database) {
|
||||
if (!@mysql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
$result = @mysql_query($sql, $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute update', mysql_error($this->dblink), $sql);
|
||||
}
|
||||
return (int) mysql_affected_rows($this->dblink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
$result = @mysql_query('SET AUTOCOMMIT=0', $this->dblink);
|
||||
$result = @mysql_query('BEGIN', $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not begin transaction', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
if ($this->database) {
|
||||
if (!@mysql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
$result = @mysql_query('COMMIT', $this->dblink);
|
||||
$result = @mysql_query('SET AUTOCOMMIT=1', $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Can not commit transaction', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
if ($this->database) {
|
||||
if (!@mysql_select_db($this->database, $this->dblink)) {
|
||||
throw new SQLException('No database selected', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
$result = @mysql_query('ROLLBACK', $this->dblink);
|
||||
$result = @mysql_query('SET AUTOCOMMIT=1', $this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not rollback transaction', mysql_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of rows affected by the data manipulation
|
||||
* query.
|
||||
*
|
||||
* @return int Number of rows affected by the last query.
|
||||
*/
|
||||
function getUpdateCount()
|
||||
{
|
||||
return (int) @mysql_affected_rows($this->dblink);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once 'creole/IdGenerator.php';
|
||||
|
||||
/**
|
||||
* MySQL IdGenerator implimenation.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.6 $
|
||||
* @package creole.drivers.mysql
|
||||
*/
|
||||
class MySQLIdGenerator 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 false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::isAfterInsert()
|
||||
*/
|
||||
public function isAfterInsert()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::getIdMethod()
|
||||
*/
|
||||
public function getIdMethod()
|
||||
{
|
||||
return self::AUTOINCREMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last-generated auto-increment ID.
|
||||
*
|
||||
* Note that for very large values (2,147,483,648 to 9,223,372,036,854,775,807) a string
|
||||
* will be returned, because these numbers are larger than supported by PHP's native
|
||||
* numeric datatypes.
|
||||
*
|
||||
* @see IdGenerator::getId()
|
||||
*/
|
||||
public function getId($unused = null)
|
||||
{
|
||||
$insert_id = mysql_insert_id($this->conn->getResource());
|
||||
if ( $insert_id < 0 ) {
|
||||
$insert_id = null;
|
||||
$result = mysql_query('SELECT LAST_INSERT_ID()', $this->conn->getResource());
|
||||
if ( $result ) {
|
||||
$row = mysql_fetch_row($result);
|
||||
$insert_id = $row ? $row[0] : null;
|
||||
}
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLPreparedStatement.php,v 1.7 2005/12/10 13:46:55 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/PreparedStatement.php';
|
||||
require_once 'creole/common/PreparedStatementCommon.php';
|
||||
|
||||
/**
|
||||
* MySQL subclass for prepared statements.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.7 $
|
||||
* @package creole.drivers.mysql
|
||||
*/
|
||||
class MySQLPreparedStatement extends PreparedStatementCommon implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* Quotes string using native mysql function (mysql_real_escape_string()).
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function escape($str)
|
||||
{
|
||||
return mysql_real_escape_string($str, $this->conn->getResource());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLResultSet.php,v 1.24 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* MySQL implementation of ResultSet class.
|
||||
*
|
||||
* MySQL supports OFFSET / LIMIT natively; this means that no adjustments or checking
|
||||
* are performed. We will assume that if the lmitSQL() operation failed that an
|
||||
* exception was thrown, and that OFFSET/LIMIT will never be emulated for MySQL.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.24 $
|
||||
* @package creole.drivers.mysql
|
||||
*/
|
||||
class MySQLResultSet extends ResultSetCommon implements ResultSet {
|
||||
|
||||
/**
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
public function seek($rownum)
|
||||
{
|
||||
// MySQL rows start w/ 0, but this works, because we are
|
||||
// looking to move the position _before_ the next desired position
|
||||
if (!@mysql_data_seek($this->result, $rownum)) {
|
||||
return false;
|
||||
}
|
||||
$this->cursorPos = $rownum;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->fields = mysql_fetch_array($this->result, $this->fetchmode);
|
||||
|
||||
if (!$this->fields) {
|
||||
$errno = mysql_errno($this->conn->getResource());
|
||||
if (!$errno) {
|
||||
// We've advanced beyond end of recordset.
|
||||
$this->afterLast();
|
||||
return false;
|
||||
} else {
|
||||
throw new SQLException("Error fetching result", mysql_error($this->conn->getResource()));
|
||||
}
|
||||
}
|
||||
|
||||
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 = @mysql_num_rows($this->result);
|
||||
if ($rows === null) {
|
||||
throw new SQLException("Error fetching num rows", mysql_error($this->conn->getResource()));
|
||||
}
|
||||
return (int) $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
@mysql_free_result($this->result);
|
||||
$this->fields = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string version of column.
|
||||
* No rtrim() necessary for MySQL, as this happens natively.
|
||||
* @see ResultSet::getString()
|
||||
*/
|
||||
public function getString($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
return (string) $this->fields[$idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unix epoch timestamp based on either a TIMESTAMP or DATETIME field.
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1.
|
||||
* @return string
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
function getTimestamp($column, $format='Y-m-d H:i:s')
|
||||
{
|
||||
if (is_int($column)) { $column--; } // because Java convention is to start at 1
|
||||
if (!array_key_exists($column, $this->fields)) { throw new SQLException("Invalid resultset column: " . (is_int($column) ? $column + 1 : $column)); }
|
||||
if ($this->fields[$column] === null) { return null; }
|
||||
|
||||
$ts = strtotime($this->fields[$column]);
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
// otherwise it's an ugly MySQL timestamp!
|
||||
// YYYYMMDDHHMMSS
|
||||
if (preg_match('/([\d]{4})([\d]{2})([\d]{2})([\d]{2})([\d]{2})([\d]{2})/', $this->fields[$column], $matches)) {
|
||||
// YYYY MM DD HH MM SS
|
||||
// $1 $2 $3 $4 $5 $6
|
||||
$ts = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
|
||||
}
|
||||
}
|
||||
if ($ts === -1 || $ts === false) { // if it's still -1, then there's nothing to be done; use a different method.
|
||||
throw new SQLException("Unable to convert value at column " . (is_int($column) ? $column + 1 : $column) . " to timestamp: " . $this->fields[$column]);
|
||||
}
|
||||
if ($format === null) {
|
||||
return $ts;
|
||||
}
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLStatement.php,v 1.1 2004/02/19 02:49:42 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';
|
||||
|
||||
/**
|
||||
* MySQL Statement
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @author Stig Bakken <ssb@fast.no>
|
||||
* @author Lukas Smith
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.mysql
|
||||
*/
|
||||
class MySQLStatement extends StatementCommon implements Statement {
|
||||
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: MySQLTypes.php,v 1.8 2005/02/10 09:22:40 pachanga 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';
|
||||
|
||||
/**
|
||||
* MySQL types / type map.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.8 $
|
||||
* @package creole.drivers.mysql
|
||||
*/
|
||||
class MySQLTypes extends CreoleTypes {
|
||||
|
||||
/** Map MySQL native types to Creole (JDBC) types. */
|
||||
private static $typeMap = array(
|
||||
'tinyint' => CreoleTypes::TINYINT,
|
||||
'smallint' => CreoleTypes::SMALLINT,
|
||||
'mediumint' => CreoleTypes::SMALLINT,
|
||||
'int' => CreoleTypes::INTEGER,
|
||||
'integer' => CreoleTypes::INTEGER,
|
||||
'bigint' => CreoleTypes::BIGINT,
|
||||
'int24' => CreoleTypes::BIGINT,
|
||||
'real' => CreoleTypes::REAL,
|
||||
'float' => CreoleTypes::FLOAT,
|
||||
'decimal' => CreoleTypes::DECIMAL,
|
||||
'numeric' => CreoleTypes::NUMERIC,
|
||||
'double' => CreoleTypes::DOUBLE,
|
||||
'char' => CreoleTypes::CHAR,
|
||||
'varchar' => CreoleTypes::VARCHAR,
|
||||
'date' => CreoleTypes::DATE,
|
||||
'time' => CreoleTypes::TIME,
|
||||
'year' => CreoleTypes::YEAR,
|
||||
'datetime' => CreoleTypes::TIMESTAMP,
|
||||
'timestamp' => CreoleTypes::TIMESTAMP,
|
||||
'tinyblob' => CreoleTypes::BINARY,
|
||||
'blob' => CreoleTypes::VARBINARY,
|
||||
'mediumblob' => CreoleTypes::VARBINARY,
|
||||
'longblob' => CreoleTypes::VARBINARY,
|
||||
'longtext' => CreoleTypes::LONGVARCHAR,
|
||||
'tinytext' => CreoleTypes::VARCHAR,
|
||||
'mediumtext' => CreoleTypes::LONGVARCHAR,
|
||||
'text' => CreoleTypes::LONGVARCHAR,
|
||||
'enum' => CreoleTypes::CHAR,
|
||||
'set' => CreoleTypes::CHAR,
|
||||
);
|
||||
|
||||
/** 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 = strtolower($nativeType);
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLDatabaseInfo.php,v 1.13 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* MySQL implementation of DatabaseInfo.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.13 $
|
||||
* @package creole.drivers.mysql.metadata
|
||||
*/
|
||||
class MySQLDatabaseInfo extends DatabaseInfo {
|
||||
|
||||
/**
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function initTables()
|
||||
{
|
||||
include_once 'creole/drivers/mysql/metadata/MySQLTableInfo.php';
|
||||
// using $this->dblink was causing tests to break
|
||||
// perhaps dblink is changed by another test ... ?
|
||||
$result = @mysql_query("SHOW TABLES FROM `" . $this->dbname . "`", $this->conn->getResource());
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list tables", mysql_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
while ($row = mysql_fetch_row($result)) {
|
||||
$this->tables[strtoupper($row[0])] = new MySQLTableInfo($this, $row[0]);
|
||||
}
|
||||
|
||||
$this->tablesLoaded = true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL does not support sequences.
|
||||
*
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function initSequences()
|
||||
{
|
||||
// throw new SQLException("MySQL does not support sequences natively.");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,252 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLTableInfo.php,v 1.20 2006/01/17 19:44:39 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/TableInfo.php';
|
||||
|
||||
/**
|
||||
* MySQL implementation of TableInfo.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.20 $
|
||||
* @package creole.drivers.mysql.metadata
|
||||
*/
|
||||
class MySQLTableInfo extends TableInfo {
|
||||
|
||||
/** Loads the columns for this table. */
|
||||
protected function initColumns()
|
||||
{
|
||||
include_once 'creole/metadata/ColumnInfo.php';
|
||||
include_once 'creole/drivers/mysql/MySQLTypes.php';
|
||||
|
||||
if (!@mysql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
// To get all of the attributes we need, we use
|
||||
// the MySQL "SHOW COLUMNS FROM $tablename" SQL. We cannot
|
||||
// use the API functions (e.g. mysql_list_fields() because they
|
||||
// do not return complete information -- e.g. precision / scale, default
|
||||
// values).
|
||||
|
||||
$res = mysql_query("SHOW COLUMNS FROM `" . $this->name . "`", $this->conn->getResource());
|
||||
|
||||
$defaults = array();
|
||||
$nativeTypes = array();
|
||||
$precisions = array();
|
||||
|
||||
while($row = mysql_fetch_assoc($res)) {
|
||||
$name = $row['Field'];
|
||||
$is_nullable = ($row['Null'] == 'YES');
|
||||
$is_auto_increment = (strpos($row['Extra'], 'auto_increment') !== false);
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
if (preg_match('/^(\w+)[\(]?([\d,]*)[\)]?( |$)/', $row['Type'], $matches)) {
|
||||
// colname[1] size/precision[2]
|
||||
$nativeType = $matches[1];
|
||||
if ($matches[2]) {
|
||||
if ( ($cpos = strpos($matches[2], ',')) !== false) {
|
||||
$size = (int) substr($matches[2], 0, $cpos);
|
||||
$precision = $size;
|
||||
$scale = (int) substr($matches[2], $cpos + 1);
|
||||
} else {
|
||||
$size = (int) $matches[2];
|
||||
}
|
||||
}
|
||||
} elseif (preg_match('/^(\w+)\(/', $row['Type'], $matches)) {
|
||||
$nativeType = $matches[1];
|
||||
} else {
|
||||
$nativeType = $row['Type'];
|
||||
}
|
||||
//BLOBs can't have any default values in MySQL
|
||||
$default = preg_match('~blob|text~', $nativeType) ? null : $row['Default'];
|
||||
$this->columns[$name] = new ColumnInfo($this,
|
||||
$name,
|
||||
MySQLTypes::getType($nativeType),
|
||||
$nativeType,
|
||||
$size,
|
||||
$precision,
|
||||
$scale,
|
||||
$is_nullable,
|
||||
$default,
|
||||
$is_auto_increment,
|
||||
$row);
|
||||
}
|
||||
|
||||
$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();
|
||||
|
||||
if (!@mysql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
// Primary Keys
|
||||
$res = mysql_query("SHOW KEYS FROM `" . $this->name . "`", $this->conn->getResource());
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
|
||||
while($row = mysql_fetch_assoc($res)) {
|
||||
// Skip any non-primary keys.
|
||||
if ($row['Key_name'] !== 'PRIMARY') {
|
||||
continue;
|
||||
}
|
||||
$name = $row["Column_name"];
|
||||
if (!isset($this->primaryKey)) {
|
||||
$this->primaryKey = new PrimaryKeyInfo($name, $row);
|
||||
}
|
||||
$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();
|
||||
|
||||
if (!@mysql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
|
||||
// Indexes
|
||||
$res = mysql_query("SHOW INDEX FROM `" . $this->name . "`", $this->conn->getResource());
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
|
||||
while($row = mysql_fetch_assoc($res)) {
|
||||
$colName = $row["Column_name"];
|
||||
$name = $row["Key_name"];
|
||||
|
||||
if($name == "PRIMARY") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($this->indexes[$name])) {
|
||||
$isUnique = ($row["Non_unique"] == 0);
|
||||
$this->indexes[$name] = new IndexInfo($name, $isUnique, $row);
|
||||
}
|
||||
$this->indexes[$name]->addColumn($this->columns[$colName]);
|
||||
}
|
||||
|
||||
$this->indexesLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load foreign keys for supporting versions of MySQL.
|
||||
* @author Tony Bibbs
|
||||
*/
|
||||
protected function initForeignKeys() {
|
||||
|
||||
// First make sure we have supported version of MySQL:
|
||||
$res = mysql_query("SELECT VERSION()");
|
||||
$row = mysql_fetch_row($res);
|
||||
|
||||
// Yes, it is OK to hardcode this...this was the first version of MySQL
|
||||
// that supported foreign keys
|
||||
if ($row[0] < '3.23.44') {
|
||||
$this->fksLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
include_once 'creole/metadata/ForeignKeyInfo.php';
|
||||
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
if (!@mysql_select_db($this->dbname, $this->conn->getResource())) {
|
||||
throw new SQLException('No database selected');
|
||||
}
|
||||
// Get the CREATE TABLE syntax
|
||||
$res = mysql_query("SHOW CREATE TABLE `" . $this->name . "`", $this->conn->getResource());
|
||||
$row = mysql_fetch_row($res);
|
||||
|
||||
// Get the information on all the foreign keys
|
||||
$regEx = '/FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)(.*)/';
|
||||
if (preg_match_all($regEx,$row[1],$matches)) {
|
||||
$tmpArray = array_keys($matches[0]);
|
||||
foreach ($tmpArray as $curKey) {
|
||||
$name = $matches[1][$curKey];
|
||||
$ftbl = $matches[2][$curKey];
|
||||
$fcol = $matches[3][$curKey];
|
||||
$fkey = $matches[4][$curKey];
|
||||
if (!isset($this->foreignKeys[$name])) {
|
||||
$this->foreignKeys[$name] = new ForeignKeyInfo($name);
|
||||
if ($this->database->hasTable($ftbl)) {
|
||||
$foreignTable = $this->database->getTable($ftbl);
|
||||
} else {
|
||||
$foreignTable = new MySQLTableInfo($this->database, $ftbl);
|
||||
$this->database->addTable($foreignTable);
|
||||
}
|
||||
if ($foreignTable->hasColumn($fcol)) {
|
||||
$foreignCol = $foreignTable->getColumn($fcol);
|
||||
} else {
|
||||
$foreignCol = new ColumnInfo($foreignTable, $fcol);
|
||||
$foreignTable->addColumn($foreignCol);
|
||||
}
|
||||
|
||||
//typical for mysql is RESTRICT
|
||||
$fkactions = array(
|
||||
'ON DELETE' => ForeignKeyInfo::RESTRICT,
|
||||
'ON UPDATE' => ForeignKeyInfo::RESTRICT,
|
||||
);
|
||||
|
||||
if ($fkey) {
|
||||
//split foreign key information -> search for ON DELETE and afterwords for ON UPDATE action
|
||||
foreach (array_keys($fkactions) as $fkaction) {
|
||||
$result = NULL;
|
||||
preg_match('/' . $fkaction . ' (' . ForeignKeyInfo::CASCADE . '|' . ForeignKeyInfo::SETNULL . ')/', $fkey, $result);
|
||||
if ($result && is_array($result) && isset($result[1])) {
|
||||
$fkactions[$fkaction] = $result[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->foreignKeys[$name]->addReference($this->columns[$name], $foreignCol, $fkactions['ON DELETE'], $fkactions['ON UPDATE']);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->fksLoaded = true;
|
||||
|
||||
}
|
||||
|
||||
protected function initVendorSpecificInfo()
|
||||
{
|
||||
$res = mysql_query("SHOW TABLE STATUS LIKE '" . $this->name . "'", $this->conn->getResource());
|
||||
$this->vendorSpecificInfo = mysql_fetch_assoc($res);
|
||||
|
||||
$this->vendorLoaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiConnection.php,v 1.7 2004/09/18 09:29:22 sb 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/mysqli/MySQLiResultSet.php';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of Connection.
|
||||
*
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.7 $
|
||||
* @package creole.drivers.mysqli
|
||||
*/
|
||||
class MySQLiConnection extends ConnectionCommon implements Connection {
|
||||
|
||||
/**
|
||||
* Connect to a database and log in as the specified user.
|
||||
*
|
||||
* @param $dsn the data source name (see DB::parseDSN for syntax)
|
||||
* @param $flags Any conneciton flags.
|
||||
* @access public
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
public function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
if (!extension_loaded('mysqli')) {
|
||||
throw new SQLException('mysqli extension not loaded');
|
||||
}
|
||||
|
||||
$this->dsn = $dsninfo;
|
||||
$this->flags = $flags;
|
||||
|
||||
$dbhost = null;
|
||||
|
||||
if (isset($dsninfo['protocol']) && $dsninfo['protocol'] == 'unix') {
|
||||
$dbhost = ':' . $dsninfo['socket'];
|
||||
} else {
|
||||
$dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
|
||||
|
||||
if (!empty($dsninfo['port'])) {
|
||||
$dbhost .= ':' . $dsninfo['port'];
|
||||
}
|
||||
}
|
||||
|
||||
$host = !empty($dsninfo['hostspec']) ? $dsninfo['hostspec'] : null;
|
||||
$user = !empty($dsninfo['username']) ? $dsninfo['username'] : null;
|
||||
$pw = !empty($dsninfo['password']) ? $dsninfo['password'] : null;
|
||||
$port = !empty($dsninfo['port']) ? $dsninfo['port'] : null;
|
||||
$socket = !empty($dsninfo['socket']) ? $dsninfo['socket'] : null;
|
||||
$database = !empty($dsninfo['database']) ? $dsninfo['database'] : null;
|
||||
|
||||
$encoding = !empty($dsninfo['encoding']) ? $dsninfo['encoding'] : null;
|
||||
|
||||
@ini_set('track_errors', true);
|
||||
|
||||
$conn = mysqli_connect($host, $user, $pw, $database, $port, $socket);
|
||||
|
||||
@ini_restore('track_errors');
|
||||
|
||||
if (!$conn) {
|
||||
if (($err = @mysqli_error()) != '') {
|
||||
throw new SQLException("connect failed", $err);
|
||||
} elseif (empty($php_errormsg)) {
|
||||
throw new SQLException("connect failed");
|
||||
} else {
|
||||
throw new SQLException("connect failed", $php_errormsg);
|
||||
}
|
||||
}
|
||||
|
||||
$this->dblink = $conn;
|
||||
|
||||
if ($encoding) {
|
||||
$this->executeUpdate("SET NAMES " . $encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
require_once 'creole/drivers/mysqli/metadata/MySQLiDatabaseInfo.php';
|
||||
return new MySQLiDatabaseInfo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
require_once 'creole/drivers/mysqli/MySQLiIdGenerator.php';
|
||||
return new MySQLiIdGenerator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
require_once 'creole/drivers/mysqli/MySQLiPreparedStatement.php';
|
||||
return new MySQLiPreparedStatement($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareCall()
|
||||
*/
|
||||
public function prepareCall($sql) {
|
||||
throw new SQLException('MySQL does not support stored procedures.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
require_once 'creole/drivers/mysqli/MySQLiStatement.php';
|
||||
return new MySQLiStatement($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::disconnect()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$ret = mysqli_close($this->dblink);
|
||||
$this->dblink = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ( $limit > 0 ) {
|
||||
$sql .= " LIMIT " . ($offset > 0 ? $offset . ", " : "") . $limit;
|
||||
} else if ( $offset > 0 ) {
|
||||
$sql .= " LIMIT " . $offset . ", 18446744073709551615";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeQuery()
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$this->lastQuery = $sql;
|
||||
|
||||
$result = @mysqli_query($this->dblink, $sql);
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute query', mysqli_error($this->dblink), $sql);
|
||||
}
|
||||
|
||||
return new MySQLiResultSet($this, $result, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeUpdate()
|
||||
*/
|
||||
public function executeUpdate($sql)
|
||||
{
|
||||
$this->lastQuery = $sql;
|
||||
|
||||
$result = @mysqli_query($this->dblink, $sql);
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute update', mysqli_error($this->dblink), $sql);
|
||||
}
|
||||
|
||||
return (int) mysqli_affected_rows($this->dblink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
if (!mysqli_autocommit($this->dblink, FALSE)) {
|
||||
throw new SQLException('Could not begin transaction', mysqli_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
if (!mysqli_commit($this->dblink)) {
|
||||
throw new SQLException('Can not commit transaction', mysqli_error($this->dblink));
|
||||
}
|
||||
mysqli_autocommit($this->dblink, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
if (!mysqli_rollback($this->dblink)) {
|
||||
throw new SQLException('Could not rollback transaction', mysqli_error($this->dblink));
|
||||
}
|
||||
mysqli_autocommit($this->dblink, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of rows affected by the data manipulation
|
||||
* query.
|
||||
*
|
||||
* @return int Number of rows affected by the last query.
|
||||
*/
|
||||
public function getUpdateCount()
|
||||
{
|
||||
return (int) @mysqli_affected_rows($this->dblink);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiIdGenerator.php,v 1.4 2004/09/18 09:15:49 sb 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/IdGenerator.php';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of IdGenerator.
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.4 $
|
||||
* @package creole.drivers.mysqli
|
||||
*/
|
||||
class MySQLiIdGenerator 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 false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::isAfterInsert()
|
||||
*/
|
||||
public function isAfterInsert()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::getIdMethod()
|
||||
*/
|
||||
public function getIdMethod()
|
||||
{
|
||||
return self::AUTOINCREMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last-generated auto-increment ID.
|
||||
*
|
||||
* Note that for very large values (2,147,483,648 to 9,223,372,036,854,775,807) a string
|
||||
* will be returned, because these numbers are larger than supported by PHP's native
|
||||
* numeric datatypes.
|
||||
*
|
||||
* @see IdGenerator::getId()
|
||||
*/
|
||||
public function getId($unused = null)
|
||||
{
|
||||
$resource = $this->conn->getResource();
|
||||
$insert_id = mysqli_insert_id($resource);
|
||||
|
||||
if ( $insert_id < 0 ) {
|
||||
$insert_id = null;
|
||||
|
||||
$result = mysqli_query($resource, 'SELECT LAST_INSERT_ID()');
|
||||
|
||||
if ( $result ) {
|
||||
$row = mysqli_fetch_row($result);
|
||||
$insert_id = $row ? $row[0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $insert_id;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiPreparedStatement.php,v 1.3 2004/09/18 09:15:49 sb 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';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of PreparedStatement.
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.mysqli
|
||||
*/
|
||||
class MySQLiPreparedStatement extends PreparedStatementCommon implements PreparedStatement {
|
||||
/**
|
||||
* Quotes string using native MySQL function.
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function escape($str)
|
||||
{
|
||||
return mysqli_real_escape_string($this->getConnection()->getResource(), $str);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiResultSet.php,v 1.5 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of ResultSet.
|
||||
*
|
||||
* MySQL supports OFFSET / LIMIT natively; this means that no adjustments or checking
|
||||
* are performed. We will assume that if the lmitSQL() operation failed that an
|
||||
* exception was thrown, and that OFFSET/LIMIT will never be emulated for MySQL.
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.5 $
|
||||
* @package creole.drivers.mysqli
|
||||
*/
|
||||
class MySQLiResultSet extends ResultSetCommon implements ResultSet {
|
||||
/**
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
public function seek($rownum)
|
||||
{
|
||||
// MySQL rows start w/ 0, but this works, because we are
|
||||
// looking to move the position _before_ the next desired position
|
||||
if (!@mysqli_data_seek($this->result, $rownum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cursorPos = $rownum;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->fields = mysqli_fetch_array($this->result, $this->fetchmode);
|
||||
$resource = $this->conn->getResource();
|
||||
|
||||
if (!$this->fields) {
|
||||
$errno = mysqli_errno($resource);
|
||||
|
||||
if (!$errno) {
|
||||
// We've advanced beyond end of recordset.
|
||||
$this->afterLast();
|
||||
return false;
|
||||
} else {
|
||||
throw new SQLException("Error fetching result", mysqli_error($resource));
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
*/
|
||||
public function getRecordCount()
|
||||
{
|
||||
$rows = @mysqli_num_rows($this->result);
|
||||
|
||||
if ($rows === null) {
|
||||
throw new SQLException("Error fetching num rows", mysqli_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
return (int) $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::close()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@mysqli_free_result($this->result);
|
||||
$this->fields = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string version of column.
|
||||
* No rtrim() necessary for MySQL, as this happens natively.
|
||||
* @see ResultSet::getString()
|
||||
*/
|
||||
public function getString($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
|
||||
if (!array_key_exists($idx, $this->fields)) {
|
||||
throw new SQLException("Invalid resultset column: " . $column);
|
||||
}
|
||||
|
||||
if ($this->fields[$idx] === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $this->fields[$idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unix epoch timestamp based on either a TIMESTAMP or DATETIME field.
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1.
|
||||
* @return string
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getTimestamp($column, $format='Y-m-d H:i:s')
|
||||
{
|
||||
if (is_int($column)) {
|
||||
// because Java convention is to start at 1
|
||||
$column--;
|
||||
}
|
||||
|
||||
if (!array_key_exists($column, $this->fields)) {
|
||||
throw new SQLException("Invalid resultset column: " . (is_int($column) ? $column + 1 : $column));
|
||||
}
|
||||
|
||||
if ($this->fields[$column] === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$ts = strtotime($this->fields[$column]);
|
||||
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
// otherwise it's an ugly MySQL timestamp!
|
||||
// YYYYMMDDHHMMSS
|
||||
if (preg_match('/([\d]{4})([\d]{2})([\d]{2})([\d]{2})([\d]{2})([\d]{2})/', $this->fields[$column], $matches)) {
|
||||
// YYYY MM DD HH MM SS
|
||||
// $1 $2 $3 $4 $5 $6
|
||||
$ts = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE
|
||||
// if it's still -1, then there's nothing to be done; use a different method.
|
||||
throw new SQLException("Unable to convert value at column " . (is_int($column) ? $column + 1 : $column) . " to timestamp: " . $this->fields[$column]);
|
||||
}
|
||||
|
||||
if ($format === null) {
|
||||
return $ts;
|
||||
}
|
||||
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $ts);
|
||||
} else {
|
||||
return date($format, $ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiStatement.php,v 1.2 2004/09/18 09:15:49 sb 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';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of Statement.
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.2 $
|
||||
* @package creole.drivers.mysqli
|
||||
*/
|
||||
class MySQLiStatement extends StatementCommon implements Statement {
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiDatabaseInfo.php,v 1.3 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of DatabaseInfo.
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.mysqli.metadata
|
||||
*/
|
||||
class MySQLiDatabaseInfo extends DatabaseInfo {
|
||||
/**
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function initTables()
|
||||
{
|
||||
include_once 'creole/drivers/mysqli/metadata/MySQLiTableInfo.php';
|
||||
|
||||
$result = @mysqli_query($this->conn->getResource(), 'SHOW TABLES FROM ' . $this->dbname);
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list tables", mysqli_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
while ($row = mysqli_fetch_row($result)) {
|
||||
$this->tables[strtoupper($row[0])] = new MySQLiTableInfo($this, $row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL does not support sequences.
|
||||
*
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function initSequences()
|
||||
{
|
||||
// throw new SQLException("MySQL does not support sequences natively.");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLiTableInfo.php,v 1.3 2006/01/17 19:44:39 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/TableInfo.php';
|
||||
|
||||
/**
|
||||
* MySQLi implementation of TableInfo.
|
||||
*
|
||||
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.mysqli.metadata
|
||||
*/
|
||||
class MySQLiTableInfo extends TableInfo {
|
||||
/** Loads the columns for this table. */
|
||||
protected function initColumns()
|
||||
{
|
||||
require_once 'creole/metadata/ColumnInfo.php';
|
||||
require_once 'creole/drivers/mysql/MySQLTypes.php';
|
||||
|
||||
// To get all of the attributes we need, we use
|
||||
// the MySQL "SHOW COLUMNS FROM $tablename" SQL.
|
||||
$res = mysqli_query($this->conn->getResource(), "SHOW COLUMNS FROM " . $this->name);
|
||||
|
||||
$defaults = array();
|
||||
$nativeTypes = array();
|
||||
$precisions = array();
|
||||
|
||||
while($row = mysqli_fetch_assoc($res)) {
|
||||
$name = $row['Field'];
|
||||
$default = $row['Default'];
|
||||
$is_nullable = ($row['Null'] == 'YES');
|
||||
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
if (preg_match('/^(\w+)[\(]?([\d,]*)[\)]?( |$)/', $row['Type'], $matches)) {
|
||||
// colname[1] size/precision[2]
|
||||
$nativeType = $matches[1];
|
||||
if ($matches[2]) {
|
||||
if ( ($cpos = strpos($matches[2], ',')) !== false) {
|
||||
$size = (int) substr($matches[2], 0, $cpos);
|
||||
$precision = $size;
|
||||
$scale = (int) substr($matches[2], $cpos + 1);
|
||||
} else {
|
||||
$size = (int) $matches[2];
|
||||
}
|
||||
}
|
||||
} elseif (preg_match('/^(\w+)\(/', $row['Type'], $matches)) {
|
||||
$nativeType = $matches[1];
|
||||
} else {
|
||||
$nativeType = $row['Type'];
|
||||
}
|
||||
|
||||
$this->columns[$name] = new ColumnInfo($this, $name, MySQLTypes::getType($nativeType), $nativeType, $size, $precision, $scale, $is_nullable, $default);
|
||||
}
|
||||
|
||||
$this->colsLoaded = true;
|
||||
}
|
||||
|
||||
/** Loads the primary key information for this table. */
|
||||
protected function initPrimaryKey()
|
||||
{
|
||||
require_once 'creole/metadata/PrimaryKeyInfo.php';
|
||||
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) {
|
||||
$this->initColumns();
|
||||
}
|
||||
|
||||
// Primary Keys
|
||||
$res = mysqli_query($this->conn->getResource(), "SHOW KEYS FROM " . $this->name);
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
while($row = mysqli_fetch_assoc($res)) {
|
||||
$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() {
|
||||
require_once 'creole/metadata/IndexInfo.php';
|
||||
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) {
|
||||
$this->initColumns();
|
||||
}
|
||||
|
||||
// Indexes
|
||||
$res = mysqli_query($this->conn->getResource(), "SHOW INDEX FROM " . $this->name);
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
while($row = mysqli_fetch_assoc($res)) {
|
||||
$name = $row["Column_name"];
|
||||
|
||||
if (!isset($this->indexes[$name])) {
|
||||
$this->indexes[$name] = new IndexInfo($name);
|
||||
}
|
||||
|
||||
$this->indexes[$name]->addColumn($this->columns[ $name ]);
|
||||
}
|
||||
|
||||
$this->indexesLoaded = true;
|
||||
}
|
||||
|
||||
/** Load foreign keys (unsupported in MySQL). */
|
||||
protected function initForeignKeys() {
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) {
|
||||
$this->initColumns();
|
||||
}
|
||||
|
||||
// Foreign keys are not supported in mysql.
|
||||
$this->fksLoaded = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCCachedResultSet.php,v 1.2 2005/04/01 17:04:00 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/drivers/odbc/ODBCResultSetCommon.php';
|
||||
require_once 'creole/drivers/odbc/ODBCTypes.php';
|
||||
|
||||
/**
|
||||
* ODBC implementation of a cached ResultSet.
|
||||
*
|
||||
* In addition to limit/offset emulation, this class implements a resultset
|
||||
* cache. This can be useful as a workaround for some ODBC drivers which lack
|
||||
* support for reverse/absolute cursor scrolling, etc.
|
||||
*
|
||||
* This class will cache rows _on-demand_. So if you only read the first couple
|
||||
* rows of a result, then only those rows will be cached. However, note that if
|
||||
* you call getRecordCount() or last(), the class must read and cache all
|
||||
* available records.
|
||||
*
|
||||
* The offset / limit variables are also taken into account when caching. Any
|
||||
* rows preceding the offset value will be skipped. Caching will stop once the
|
||||
* limit value is reached.
|
||||
*
|
||||
* To use this class, create a derived {@link ODBCAdapter} class which returns
|
||||
* an instance of ODBCCachedResultSet from the {@link ODBCAdapter::createResultSet()} method.
|
||||
* Specify the adapter via the query portion of the Connection URL:
|
||||
*
|
||||
* odbc://localhost/Driver=MySQL ODBC 3.51 Driver;Database=test?adapter=MySQL
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.2 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCCachedResultSet extends ODBCResultSetCommon implements ResultSet
|
||||
{
|
||||
/**
|
||||
* Record cache
|
||||
* @var array
|
||||
*/
|
||||
protected $recs = array();
|
||||
|
||||
/**
|
||||
* Tracks the last cursor position of the recordset.
|
||||
* @var integer
|
||||
*/
|
||||
protected $lastPos = -1;
|
||||
|
||||
/**
|
||||
* True if blobs/clobs should also be cached.
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheLobs = false;
|
||||
|
||||
/**
|
||||
* @see ResultSet::__construct()
|
||||
*/
|
||||
public function __construct(Connection $conn, $result, $fetchmode = null, $cacheLobs = false)
|
||||
{
|
||||
parent::__construct($conn, $result, $fetchmode);
|
||||
|
||||
$this->cacheLobs = $cacheLobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ODBCResultSetCommon::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
parent::close();
|
||||
$this->recs = null;
|
||||
$this->lastPos = -1;
|
||||
$this->cacheLobs = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches specified records up to and including the specified 1-based
|
||||
* record position. If -1 is specified, all records will be cached.
|
||||
* @param integer Maximum record position to cache.
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
public function loadCache($recPos = -1)
|
||||
{
|
||||
$rid = $this->result->getHandle();
|
||||
|
||||
$curRecs = count($this->recs);
|
||||
$totRecs = ($curRecs ? $this->offset + $curRecs : 0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Is record already cached?
|
||||
if ($this->lastPos != -1 || ($recPos > -1 && $recPos <= $curRecs))
|
||||
return;
|
||||
|
||||
// Fetch row (no buffers copied yet).
|
||||
$rowNum = ++$totRecs;
|
||||
$result = @odbc_fetch_row($rid, $rowNum);
|
||||
|
||||
// All records cached?
|
||||
if ($result === false || ($this->limit > 0 && $curRecs+1 > $this->limit))
|
||||
{
|
||||
$this->lastPos = $curRecs;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore offset records.
|
||||
if ($totRecs <= $this->offset)
|
||||
continue;
|
||||
|
||||
// Load row array.
|
||||
$row = array();
|
||||
for ($i = 0, $n = @odbc_num_fields($rid); $i < $n; $i++)
|
||||
{
|
||||
$fldNum = $i+1;
|
||||
$row[$i] = odbc_result($rid, $fldNum);
|
||||
|
||||
// Cache lobs if necessary
|
||||
if ($this->cacheLobs)
|
||||
{
|
||||
ODBCTypes::loadTypeMap($this->conn);
|
||||
|
||||
$nativeType = @odbc_field_type($rid, $fldNum);
|
||||
$creoleType = ODBCTypes::getType($nativeType);
|
||||
|
||||
$isBlob = ($creoleType == CreoleTypes::BLOB ||
|
||||
$creoleType == CreoleTypes::LONGVARBINARY);
|
||||
|
||||
$isClob = ($creoleType == CreoleTypes::CLOB ||
|
||||
$creoleType == CreoleTypes::LONGVARCHAR);
|
||||
|
||||
if (($isBlob || $isClob) && $row[$i] !== null)
|
||||
{
|
||||
$binmode = ($isBlob ? ODBC_BINMODE_RETURN : ODBC_BINMODE_CONVERT);
|
||||
$curdata = $row[$i];
|
||||
$row[$i] = $this->readLobData($fldNum, $binmode, $curdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add record to cache.
|
||||
$this->recs[++$curRecs] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
public function seek($rownum)
|
||||
{
|
||||
$this->loadCache($rownum);
|
||||
|
||||
if ($rownum < 0 || $rownum > count($this->recs)+1)
|
||||
return false;
|
||||
|
||||
$this->cursorPos = $rownum;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
$this->loadCache(++$this->cursorPos);
|
||||
|
||||
if ($this->isAfterLast())
|
||||
{
|
||||
$this->afterLast();
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->fields =& $this->checkFetchMode($this->recs[$this->cursorPos]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getRecordCount()
|
||||
*/
|
||||
function getRecordCount()
|
||||
{
|
||||
if ($this->lastPos == -1)
|
||||
$this->loadCache(-1);
|
||||
|
||||
return $this->lastPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::isAfterLast()
|
||||
*/
|
||||
public function isAfterLast()
|
||||
{
|
||||
// All records cached yet?
|
||||
if ($this->lastPos == -1)
|
||||
return false;
|
||||
|
||||
return ($this->cursorPos > $this->lastPos);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,362 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCConnection.php,v 1.6 2006/01/17 19:44:39 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/Connection.php';
|
||||
require_once 'creole/common/ConnectionCommon.php';
|
||||
require_once 'creole/drivers/odbc/adapters/ODBCAdapter.php';
|
||||
|
||||
/**
|
||||
* ODBC implementation of Connection.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.6 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCConnection extends ConnectionCommon implements Connection {
|
||||
|
||||
/**
|
||||
* Implements driver-specific behavior
|
||||
* @var ODBCAdapter
|
||||
*/
|
||||
protected $adapter = null;
|
||||
|
||||
/**
|
||||
* Last ODBC result resource from executeQuery/executeUpdate. Used in getUpdateCount()
|
||||
* @var ODBCResultResource
|
||||
*/
|
||||
protected $odbcresult = null;
|
||||
|
||||
/**
|
||||
* @see Connection::connect()
|
||||
*/
|
||||
public function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
if (!function_exists('odbc_connect'))
|
||||
throw new SQLException('odbc extension not loaded');
|
||||
|
||||
$adapterclass = isset($dsninfo['adapter']) ? $dsninfo['adapter'] : null;
|
||||
|
||||
if (!$adapterclass)
|
||||
$adapterclass = 'ODBCAdapter';
|
||||
else
|
||||
$adapterclass .= 'Adapter';
|
||||
|
||||
Creole::import('creole.drivers.odbc.adapters.' . $adapterclass);
|
||||
$this->adapter = new $adapterclass();
|
||||
|
||||
$this->dsn = $dsninfo;
|
||||
$this->flags = $flags;
|
||||
|
||||
if ( !($this->flags & Creole::COMPAT_ASSOC_LOWER) && !$this->adapter->preservesColumnCase())
|
||||
{
|
||||
trigger_error('Connection created without Creole::COMPAT_ASSOC_LOWER, ' .
|
||||
'but driver does not support case preservation.',
|
||||
E_USER_WARNING);
|
||||
$this->flags != Creole::COMPAT_ASSOC_LOWER;
|
||||
}
|
||||
|
||||
$persistent = ($flags & Creole::PERSISTENT) === Creole::PERSISTENT;
|
||||
|
||||
if ($dsninfo['database'])
|
||||
$odbcdsn = $dsninfo['database'];
|
||||
elseif ($dsninfo['hostspec'])
|
||||
$odbcdsn = $dsninfo['hostspec'];
|
||||
else
|
||||
$odbcdsn = 'localhost';
|
||||
|
||||
$user = @$dsninfo['username'];
|
||||
$pw = @$dsninfo['password'];
|
||||
|
||||
$connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect';
|
||||
|
||||
$conn = @$connect_function($odbcdsn, $user, $pw, SQL_CUR_USE_IF_NEEDED);
|
||||
|
||||
if (!is_resource($conn))
|
||||
throw new SQLException('connect failed', $this->nativeError(), $odbcdsn);
|
||||
|
||||
$this->dblink = $conn;
|
||||
|
||||
/**
|
||||
* This prevents blob fields from being fetched when a row is loaded
|
||||
* from a recordset. Clob fields however are loaded with up to
|
||||
* 'odbc.defaultlrl' data. This should be the default anyway, but we'll
|
||||
* set it here just to keep things consistent.
|
||||
*/
|
||||
@odbc_binmode(0, ODBC_BINMODE_PASSTHRU);
|
||||
@odbc_longreadlen(0, ini_get('odbc.defaultlrl'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::close()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$ret = true;
|
||||
|
||||
$this->adapter = null;
|
||||
$this->odbcresult = null;
|
||||
|
||||
if ($this->dblink !== null)
|
||||
{
|
||||
$ret = @odbc_close($this->dblink);
|
||||
$this->dblink = null;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shouldn't this be in ConnectionCommon.php?
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted ODBC error string.
|
||||
* @return string
|
||||
*/
|
||||
public function nativeError()
|
||||
{
|
||||
if ($this->dblink && is_resource($this->dblink))
|
||||
$errstr = '[' . @odbc_error($this->dblink) . '] ' . @odbc_errormsg($this->dblink);
|
||||
else
|
||||
$errstr = '[' . @odbc_error() . '] ' . @odbc_errormsg();
|
||||
|
||||
return $errstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns driver-specific ODBCAdapter.
|
||||
* @return ODBCAdapter
|
||||
*/
|
||||
public function getAdapter()
|
||||
{
|
||||
return $this->adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
require_once 'creole/drivers/odbc/metadata/ODBCDatabaseInfo.php';
|
||||
return new ODBCDatabaseInfo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
return $this->adapter->getIdGenerator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the appropriate ResultSet
|
||||
* @return ResultSet
|
||||
*/
|
||||
public function createResultSet($odbcresult, $fetchmode)
|
||||
{
|
||||
return $this->adapter->createResultSet($this, $odbcresult, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
require_once 'creole/drivers/odbc/ODBCPreparedStatement.php';
|
||||
return new ODBCPreparedStatement($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
require_once 'creole/drivers/odbc/ODBCStatement.php';
|
||||
return new ODBCStatement($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo To be implemented
|
||||
* @see Connection::prepareCall()
|
||||
*/
|
||||
public function prepareCall($sql)
|
||||
{
|
||||
throw new SQLException('Stored procedures not currently implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ($this->adapter->hasLimitOffset())
|
||||
$this->adapter->applyLimit($sql, $offset, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeQuery()
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
if ($this->odbcresult)
|
||||
$this->odbcresult = null;
|
||||
|
||||
$r = @odbc_exec($this->dblink, $sql);
|
||||
|
||||
if ($r === false)
|
||||
throw new SQLException('Could not execute query', $this->nativeError(), $sql);
|
||||
|
||||
$this->odbcresult = new ODBCResultResource($r);
|
||||
|
||||
return $this->createResultSet($this->odbcresult, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeUpdate()
|
||||
*/
|
||||
public function executeUpdate($sql)
|
||||
{
|
||||
if ($this->odbcresult)
|
||||
$this->odbcresult = null;
|
||||
|
||||
$r = @odbc_exec($this->dblink, $sql);
|
||||
|
||||
if ($r === false)
|
||||
throw new SQLException('Could not execute update', $this->nativeError(), $sql);
|
||||
|
||||
$this->odbcresult = new ODBCResultResource($r);
|
||||
|
||||
return $this->getUpdateCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
if ($this->adapter->supportsTransactions()) {
|
||||
@odbc_autocommit($this->dblink, false);
|
||||
if (odbc_error($this->dblink) == 'S1C00') {
|
||||
throw new SQLException('Could not begin transaction', $this->nativeError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
if ($this->adapter->supportsTransactions()) {
|
||||
$result = @odbc_commit($this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not commit transaction', $this->nativeError());
|
||||
}
|
||||
@odbc_autocommit($this->dblink, true);
|
||||
if (odbc_error($this->dblink) == 'S1C00') {
|
||||
throw new SQLException('Could not commit transaction (autocommit failed)', $this->nativeError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
if ($this->adapter->supportsTransactions()) {
|
||||
$result = @odbc_rollback($this->dblink);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not rollback transaction', $this->nativeError());
|
||||
}
|
||||
@odbc_autocommit($this->dblink, true);
|
||||
if (odbc_error($this->dblink) == 'S1C00') {
|
||||
throw new SQLException('Could not rollback transaction (autocommit failed)', $this->nativeError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getUpdateCount()
|
||||
*/
|
||||
public function getUpdateCount()
|
||||
{
|
||||
if ($this->odbcresult === null)
|
||||
return 0;
|
||||
|
||||
$n = @odbc_num_rows($this->odbcresult->getHandle());
|
||||
|
||||
if ($n == -1)
|
||||
throw new SQLException('Could not retrieve update count', $this->nativeError());
|
||||
|
||||
return (int) $n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a simple wrapper class to manage the lifetime of an ODBC result resource
|
||||
* (returned by odbc_exec(), odbc_execute(), etc.) We use a separate class because
|
||||
* the resource can be shared by both ODBCConnection and an ODBCResultSet at the
|
||||
* same time. ODBCConnection hangs on to the last result resource to be used in
|
||||
* its getUpdateCount() method. It also passes this resource to new instances of
|
||||
* ODBCResultSet. At some point the resource has to be cleaned up via
|
||||
* odbc_free_result(). Using this class as a wrapper, we can pass around multiple
|
||||
* references to the same resource. PHP's reference counting mechanism will clean
|
||||
* up the resource when its no longer used via ODBCResultResource::__destruct().
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCResultResource
|
||||
{
|
||||
/**
|
||||
* @var resource ODBC result resource returned by {@link odbc_exec()}/{@link odbc_execute()}.
|
||||
*/
|
||||
protected $handle = null;
|
||||
|
||||
public function __construct($handle)
|
||||
{
|
||||
if (is_resource($handle))
|
||||
$this->handle = $handle;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->handle !== null)
|
||||
@odbc_free_result($this->handle);
|
||||
}
|
||||
|
||||
public function getHandle()
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once 'creole/IdGenerator.php';
|
||||
|
||||
/**
|
||||
* ODBC IdGenerator implimenation.
|
||||
*
|
||||
* NOTE: I tried keeping the SQL as basic as possible in this class.
|
||||
* If you need something more optimized, derive your own IdGenerator
|
||||
* and use {@link ODBCAdapter::getIdGenerator()} to use it.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.2 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCIdGenerator 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($seqname = null)
|
||||
{
|
||||
if ($seqname === null)
|
||||
throw new SQLException('You must specify the sequence name when calling getId() method.');
|
||||
|
||||
$triedcreate = false;
|
||||
|
||||
while (1)
|
||||
{
|
||||
try
|
||||
{
|
||||
$n = $this->conn->executeUpdate("UPDATE $seqname SET id = id + 1", ResultSet::FETCHMODE_NUM);
|
||||
|
||||
if ($n == 0)
|
||||
throw new SQLException('Failed to update IdGenerator id', $this->conn->nativeError());
|
||||
|
||||
$rs = $this->conn->executeQuery("SELECT id FROM $seqname", ResultSet::FETCHMODE_NUM);
|
||||
}
|
||||
catch (SQLException $e)
|
||||
{
|
||||
//$odbcerr = odbc_error($this->conn->getResource());
|
||||
|
||||
if ($triedcreate)// || ($odbcerr != 'S0000' && $odbcerr != 'S0002'))
|
||||
throw $e;
|
||||
|
||||
$this->drop($seqname, true);
|
||||
$this->create($seqname);
|
||||
$triedcreate = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$rs->first();
|
||||
|
||||
return $rs->getInt(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the sequence emulation table.
|
||||
*/
|
||||
public function create($seqname)
|
||||
{
|
||||
$this->conn->executeUpdate("CREATE TABLE $seqname ( id numeric(19,0) NOT NULL )");
|
||||
$this->conn->executeUpdate("INSERT INTO $seqname ( id ) VALUES ( 0 )");
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the sequence emulation table.
|
||||
*/
|
||||
public function drop($seqname, $ignoreerrs = false)
|
||||
{
|
||||
try {
|
||||
$this->conn->executeUpdate("DROP TABLE $seqname");
|
||||
} catch (Exception $e) {
|
||||
if (!$ignoreerrs) throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCPreparedStatement.php,v 1.4 2005/11/13 01:29:01 gamr 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';
|
||||
require_once 'creole/util/Lob.php';
|
||||
|
||||
/**
|
||||
* ODBC specific PreparedStatement functions.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.4 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCPreparedStatement extends PreparedStatementCommon implements PreparedStatement
|
||||
{
|
||||
/**
|
||||
* This does nothing since ODBC natively supports prepared statements.
|
||||
* @see PreparedStatementCommon::replaceParams()
|
||||
*/
|
||||
protected function replaceParams()
|
||||
{
|
||||
if ($this->conn->getAdapter()->emulatePrepareStmt())
|
||||
return parent::replaceParams();
|
||||
else
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to call native ODBC prepare/execute functions.
|
||||
*/
|
||||
protected function _execute($sql, $params, $fetchmode, $isupdate)
|
||||
{
|
||||
if ($this->resultSet)
|
||||
{
|
||||
$this->resultSet->close();
|
||||
$this->resultSet = null;
|
||||
}
|
||||
|
||||
$this->updateCount = null;
|
||||
|
||||
if ($this->conn->getAdapter()->emulatePrepareStmt())
|
||||
{
|
||||
$stmt = @odbc_exec($this->conn->getResource(), $sql);
|
||||
$ret = ($stmt !== false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Trim surrounding quotes added from default set methods.
|
||||
// Exception: for LOB-based parameters, odbc_execute() will
|
||||
// accept a filename surrounded by single-quotes.
|
||||
foreach ($this->boundInVars as $idx => $var)
|
||||
{
|
||||
if ($var instanceof Lob)
|
||||
{
|
||||
$file = ($isupdate ? $var->getInputFile() : $var->getOutputFile());
|
||||
$this->boundInVars[$idx] = "'$file'";
|
||||
}
|
||||
else if (is_string($var))
|
||||
{
|
||||
$this->boundInVars[$idx] = trim($var, "\"\'");
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = @odbc_prepare($this->conn->getResource(), $sql);
|
||||
|
||||
if ($stmt === FALSE)
|
||||
throw new SQLException('Could not prepare query', $this->conn->nativeError(), $sql);
|
||||
|
||||
$ret = @odbc_execute($stmt, $this->boundInVars);
|
||||
}
|
||||
|
||||
if ($ret === FALSE)
|
||||
{
|
||||
@odbc_free_result($stmt);
|
||||
throw new SQLException('Could not execute query', $this->conn->nativeError(), $sql);
|
||||
}
|
||||
|
||||
return $this->conn->createResultSet(new ODBCResultResource($stmt), $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::executeQuery()
|
||||
*/
|
||||
public function executeQuery()
|
||||
{
|
||||
switch (func_num_args()) {
|
||||
case 2:
|
||||
list($params, $fetchmode) = func_get_args();
|
||||
if (!is_array($params)) {
|
||||
unset($params);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
$params = null;
|
||||
list($fetchmode) = func_get_args();
|
||||
break;
|
||||
case 0:
|
||||
$params = null;
|
||||
$fetchmode = null;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set any params passed directly
|
||||
if (isset($params)) {
|
||||
for($i=0,$cnt=count($params); $i < $cnt; $i++) {
|
||||
$this->set($i+1, $params[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->replaceParams();
|
||||
|
||||
if ($this->conn->getAdapter()->hasLimitOffset())
|
||||
{
|
||||
if ($this->limit > 0 || $this->offset > 0)
|
||||
$this->conn->applyLimit($sql, $this->offset, $this->limit);
|
||||
}
|
||||
|
||||
$this->resultSet = $this->_execute($sql, $params, $fetchmode, false);
|
||||
|
||||
if (!$this->conn->getAdapter()->hasLimitOffset())
|
||||
{
|
||||
$this->resultSet->_setOffset($this->offset);
|
||||
$this->resultSet->_setLimit($this->limit);
|
||||
}
|
||||
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::executeUpdate()
|
||||
*/
|
||||
public function executeUpdate($params = null)
|
||||
{
|
||||
// Set any params passed directly
|
||||
if ($params) {
|
||||
for($i=0,$cnt=count($params); $i < $cnt; $i++) {
|
||||
$this->set($i+1, $params[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->replaceParams();
|
||||
$this->_execute($sql, $params, 0, true);
|
||||
$this->updateCount = $this->conn->getUpdateCount();
|
||||
|
||||
return $this->updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatementCommon::escape()
|
||||
*/
|
||||
protected function escape($str)
|
||||
{
|
||||
if ($this->conn->getAdapter()->emulatePrepareStmt())
|
||||
return $this->conn->getAdapter()->escape($str);
|
||||
|
||||
// Nothing to do here. odbc_execute() takes care of escaping strings.
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setNull()
|
||||
*/
|
||||
function setNull($paramIndex)
|
||||
{
|
||||
$this->sql_cache_valid = false;
|
||||
$this->boundInVars[$paramIndex] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setBlob()
|
||||
*/
|
||||
function setBlob($paramIndex, $blob)
|
||||
{
|
||||
if ($this->conn->getAdapter()->emulatePrepareStmt())
|
||||
return parent::setBlob($paramIndex, $blob);
|
||||
|
||||
$this->sql_cache_valid = false;
|
||||
if ($blob === null)
|
||||
{
|
||||
$this->setNull($paramIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($blob instanceof Blob)
|
||||
{
|
||||
if ($blob->isFromFile() && !$blob->isModified())
|
||||
{
|
||||
$this->boundInVars[$paramIndex] = $blob;
|
||||
return;
|
||||
}
|
||||
|
||||
$blob = $blob->__toString();
|
||||
}
|
||||
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape($blob) . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatement::setClob()
|
||||
*/
|
||||
function setClob($paramIndex, $clob)
|
||||
{
|
||||
if ($this->conn->getAdapter()->emulatePrepareStmt())
|
||||
return parent::setClob($paramIndex, $clob);
|
||||
|
||||
$this->sql_cache_valid = false;
|
||||
if ($clob === null)
|
||||
{
|
||||
$this->setNull($paramIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($clob instanceof Clob)
|
||||
{
|
||||
if ($clob->isFromFile() && !$clob->isModified())
|
||||
{
|
||||
$this->boundInVars[$paramIndex] = $clob;
|
||||
return;
|
||||
}
|
||||
|
||||
$clob = $clob->__toString();
|
||||
}
|
||||
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->escape($clob) . "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCResultSet.php,v 1.2 2005/04/01 17:10:42 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/drivers/odbc/ODBCResultSetCommon.php';
|
||||
|
||||
/**
|
||||
* ODBC implementation of ResultSet.
|
||||
*
|
||||
* If the current ODBC driver does not support LIMIT or OFFSET natively,
|
||||
* the methods in here perform some adjustments and extra checking to make
|
||||
* sure that this behaves the same as RDBMS drivers using native OFFSET/LIMIT.
|
||||
*
|
||||
* This class also emulates a row count if the driver is not capable of
|
||||
* providing one natively.
|
||||
*
|
||||
* NOTE: This class only works with drivers that support absolute cursor
|
||||
* positioning (SQL_FETCH_DIRECTION = SQL_FD_FETCH_ABSOLUTE). If the
|
||||
* driver you are using does not support reverse/absolute cursor
|
||||
* scrolling, you should use the {@link ODBCCachedResultSet} class instead.
|
||||
* See the documentation for ODBCCachedResultSet for instructions on how
|
||||
* to use it.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.2 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCResultSet extends ODBCResultSetCommon implements ResultSet
|
||||
{
|
||||
/**
|
||||
* Number of rows in resultset.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $numRows = -1;
|
||||
|
||||
/**
|
||||
* True if ODBC driver supports odbc_num_rows().
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasRowCount = false;
|
||||
|
||||
/**
|
||||
* @see ResultSet::__construct()
|
||||
*/
|
||||
public function __construct(Connection $conn, $result, $fetchmode = null)
|
||||
{
|
||||
parent::__construct($conn, $result, $fetchmode);
|
||||
|
||||
/**
|
||||
* Some ODBC drivers appear not to handle odbc_num_rows() very well when
|
||||
* more than one result handle is active at once. For example, the MySQL
|
||||
* ODBC driver always returns the number of rows for the last executed
|
||||
* result. For this reason, we'll store the row count here.
|
||||
*
|
||||
* Note also that many ODBC drivers do not support this method. In this
|
||||
* case, getRecordCount() will perform a manual count.
|
||||
*/
|
||||
$this->numRows = @odbc_num_rows($result->getHandle());
|
||||
$this->hasRowCount = $this->numRows != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ODBCResultSetCommon::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
parent::close();
|
||||
$numRows = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
public function seek($rownum)
|
||||
{
|
||||
if ($rownum < 0 || $this->limit > 0 && $rownum > $this->limit)
|
||||
return false;
|
||||
|
||||
$this->cursorPos = $rownum;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->cursorPos++;
|
||||
|
||||
if ($this->limit > 0 && $this->cursorPos > $this->limit) {
|
||||
$this->cursorPos = $this->limit+1;
|
||||
return false;
|
||||
}
|
||||
|
||||
$rowNum = $this->offset + $this->cursorPos;
|
||||
$fields = null;
|
||||
|
||||
$cols = @odbc_fetch_into($this->result->getHandle(), $fields, $rowNum);
|
||||
|
||||
if ($cols === false) {
|
||||
$this->cursorPos = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->fields =& $this->checkFetchMode($fields);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::isAfterLast()
|
||||
*/
|
||||
public function isAfterLast()
|
||||
{
|
||||
// Force calculation of last record pos.
|
||||
if ($this->cursorPos == -1)
|
||||
$this->getRecordCount();
|
||||
|
||||
return parent::isAfterLast();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getRecordCount()
|
||||
*/
|
||||
function getRecordCount()
|
||||
{
|
||||
if ($this->hasRowCount)
|
||||
{
|
||||
// Use driver row count if provided.
|
||||
$numRows = $this->numRows - $this->offset;
|
||||
|
||||
if ($this->limit > 0 && $numRows > $this->limit)
|
||||
$numRows = $this->limit;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do manual row count if driver doesn't provide one.
|
||||
if ($this->numRows == -1)
|
||||
{
|
||||
$this->numRows = 0;
|
||||
$this->beforeFirst();
|
||||
|
||||
while($this->next())
|
||||
$this->numRows++;
|
||||
}
|
||||
|
||||
$numRows = $this->numRows;
|
||||
}
|
||||
|
||||
// Cursor pos is -1 when an attempt to fetch past the last row was made
|
||||
// (or a fetch error occured).
|
||||
|
||||
if ($this->cursorPos == -1)
|
||||
$this->cursorPos = $numRows+1;
|
||||
|
||||
return $numRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getBlob()
|
||||
*/
|
||||
public function getBlob($column)
|
||||
{
|
||||
require_once 'creole/util/Blob.php';
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
$data = $this->readLobData($column, ODBC_BINMODE_RETURN, $this->fields[$idx]);
|
||||
if (!$data) { return null; }
|
||||
$b = new Blob();
|
||||
$b->setContents($data);
|
||||
return $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getClob()
|
||||
*/
|
||||
public function getClob($column)
|
||||
{
|
||||
require_once 'creole/util/Clob.php';
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
$data = $this->readLobData($column, ODBC_BINMODE_CONVERT, $this->fields[$idx]);
|
||||
if (!$data) { return null; }
|
||||
$c = new Clob();
|
||||
$c->setContents($data);
|
||||
return $c;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCResultSetCommon.php,v 1.3 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* Base class for ODBC implementation of ResultSet.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
abstract class ODBCResultSetCommon extends ResultSetCommon
|
||||
{
|
||||
/**
|
||||
* Offset at which to start reading rows (for emulated offset).
|
||||
* @var int
|
||||
*/
|
||||
protected $offset = 0;
|
||||
|
||||
/**
|
||||
* Maximum rows to retrieve, or 0 if all (for emulated limit).
|
||||
* @var int
|
||||
*/
|
||||
protected $limit = 0;
|
||||
|
||||
/**
|
||||
* @see ResultSet::__construct()
|
||||
*/
|
||||
public function __construct(Connection $conn, $result, $fetchmode = null)
|
||||
{
|
||||
parent::__construct($conn, $result, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::close()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->result = null;
|
||||
$this->conn = null;
|
||||
$this->fetchmode = null;
|
||||
$this->cursorPos = 0;
|
||||
$this->fields = null;
|
||||
$this->lowerAssocCase = false;
|
||||
$this->limit = 0;
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function exists to set offset after ResultSet is instantiated.
|
||||
* This function should be "protected" in Java sense: only available to classes in package.
|
||||
* THIS METHOD SHOULD NOT BE CALLED BY ANYTHING EXCEPTION DRIVER CLASSES.
|
||||
* @param int $offset New offset.
|
||||
* @access protected
|
||||
*/
|
||||
public function _setOffset($offset)
|
||||
{
|
||||
$this->offset = $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function exists to set limit after ResultSet is instantiated.
|
||||
* This function should be "protected" in Java sense: only available to classes in package.
|
||||
* THIS METHOD SHOULD NOT BE CALLED BY ANYTHING EXCEPTION DRIVER CLASSES.
|
||||
* @param int $limit New limit.
|
||||
* @access protected
|
||||
*/
|
||||
public function _setLimit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* If fetchmode is FETCHMODE_ASSOC, returns the 1-based field index number
|
||||
* for the specified column name. Otherwise returns 0 (false).
|
||||
* @return int
|
||||
*/
|
||||
function getFieldNum($colname)
|
||||
{
|
||||
$fieldnum = 0;
|
||||
|
||||
if ($this->fetchmode == ResultSet::FETCHMODE_ASSOC)
|
||||
{
|
||||
$keys = array_keys($this->fields);
|
||||
$fieldnum = array_search($colname, $keys);
|
||||
}
|
||||
|
||||
return $fieldnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in any unread LOB data. For long char fields, we may already
|
||||
* have up to odbc_longreadlen() bytes in the buffer. These are passed
|
||||
* in via the $curdata parm. For long binary fields, no data is read
|
||||
* initially since odbc_binmode() is set to ODBC_BINMODE_PASSTHRU.
|
||||
* This method adjusts the binmode and longreadlen to finish reading
|
||||
* these datatypes into the buffer. Returns a string with the complete
|
||||
* contents.
|
||||
*
|
||||
* @param int|string $column Column index or name to read data from.
|
||||
* @param int $binmode ODBC_BINMODE_RETURN for binary data, ODBC_BINMODE_CONVERT for char data.
|
||||
* @param string $curdata Existing LOB data already in buffer.
|
||||
* @return string
|
||||
*/
|
||||
protected function readLobData($column, $binmode, $curdata = null)
|
||||
{
|
||||
// Retrieve field num
|
||||
$fldNum = (is_int($column) ? $column : getFieldNum($column));
|
||||
|
||||
$data = $curdata;
|
||||
$newdata = null;
|
||||
|
||||
// Adjust binmode and longreadlen
|
||||
odbc_binmode($this->result->getHandle(), $binmode);
|
||||
odbc_longreadlen($this->result->getHandle(), 4096);
|
||||
|
||||
while (1)
|
||||
{
|
||||
$newdata = odbc_result($this->result->getHandle(), $fldNum);
|
||||
|
||||
if ($newdata === false)
|
||||
break;
|
||||
else
|
||||
$data .= $newdata;
|
||||
}
|
||||
|
||||
// Restore the default binmode and longreadlen
|
||||
odbc_binmode($this->result->getHandle(), ODBC_BINMODE_PASSTHRU);
|
||||
odbc_longreadlen($this->result->getHandle(), ini_get('odbc.defaultlrl'));
|
||||
|
||||
// The ODBC driver I use seems to return a string with an escaped
|
||||
// null char at the end for clob data.
|
||||
$data = rtrim($data, "\x0");
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts row fields to names if FETCHMODE_ASSOC is set.
|
||||
*
|
||||
* @param array& Row to convert.
|
||||
*
|
||||
* @return array& Converted row.
|
||||
*/
|
||||
protected function checkFetchMode(&$row)
|
||||
{
|
||||
if ($this->fetchmode == ResultSet::FETCHMODE_ASSOC)
|
||||
{
|
||||
$newrow = array();
|
||||
|
||||
for ($i = 0, $n = count($row); $i < $n; $i++)
|
||||
{
|
||||
$colname = @odbc_field_name($this->result->getHandle(), $i+1);
|
||||
|
||||
if ($this->lowerAssocCase) {
|
||||
$colname = strtolower($colname);
|
||||
}
|
||||
|
||||
$newrow[$colname] = $row[$i];
|
||||
}
|
||||
|
||||
$row =& $newrow;
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCStatement.php,v 1.1 2004/07/27 23:08:30 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';
|
||||
|
||||
/**
|
||||
* ODBC Statement
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCStatement extends StatementCommon implements Statement
|
||||
{
|
||||
/**
|
||||
* @see Statement::executeQuery()
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
if ($this->resultSet)
|
||||
{
|
||||
$this->resultSet->close();
|
||||
$this->resultSet = null;
|
||||
}
|
||||
|
||||
$this->updateCount = null;
|
||||
|
||||
if ($this->conn->getAdapter()->hasLimitOffset())
|
||||
{
|
||||
if ($this->limit > 0 || $this->offset > 0)
|
||||
$this->conn->applyLimit($sql, $this->offset, $this->limit);
|
||||
}
|
||||
|
||||
$this->resultSet = $this->conn->executeQuery($sql, $fetchmode);
|
||||
|
||||
if (!$this->conn->getAdapter()->hasLimitOffset())
|
||||
{
|
||||
$this->resultSet->_setOffset($this->offset);
|
||||
$this->resultSet->_setLimit($this->limit);
|
||||
}
|
||||
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: ODBCTypes.php,v 1.1 2004/07/27 23:08:30 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';
|
||||
|
||||
/**
|
||||
* ODBC types / type map.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCTypes extends CreoleTypes {
|
||||
|
||||
/**
|
||||
* Map ODBC native types to Creole (JDBC) types.
|
||||
*/
|
||||
protected static $typeMap = null;
|
||||
|
||||
/**
|
||||
* Reverse mapping, created on demand.
|
||||
*/
|
||||
protected static $reverseMap = null;
|
||||
|
||||
/**
|
||||
* Loads the map of ODBC data types to Creole (JDBC) types.
|
||||
*
|
||||
* NOTE: This function cannot map DBMS-specific datatypes. If you use a
|
||||
* driver which implements DBMS-specific datatypes, you will need
|
||||
* to modify/extend this class to add the correct mapping.
|
||||
*/
|
||||
public static function loadTypeMap($conn = null)
|
||||
{
|
||||
if (self::$typeMap !== null && count(self::$typeMap) > 0)
|
||||
return;
|
||||
|
||||
if ($conn == null)
|
||||
throw new SQLException('No connection specified when loading ODBC type map.');
|
||||
|
||||
self::$typeMap = array();
|
||||
|
||||
$result = @odbc_gettypeinfo($conn->getResource());
|
||||
|
||||
if ($result === false)
|
||||
throw new SQLException('Failed to retrieve type info.', $conn->nativeError());
|
||||
|
||||
$rowNum = 1;
|
||||
|
||||
while (odbc_fetch_row($result, $rowNum++))
|
||||
{
|
||||
$odbctypeid = odbc_result($result, 'DATA_TYPE');
|
||||
$odbctypename = odbc_result($result, 'TYPE_NAME');
|
||||
|
||||
switch ($odbctypeid)
|
||||
{
|
||||
case SQL_CHAR:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::CHAR;
|
||||
break;
|
||||
case SQL_VARCHAR:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::VARCHAR;
|
||||
break;
|
||||
case SQL_LONGVARCHAR:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::LONGVARCHAR;
|
||||
break;
|
||||
case SQL_DECIMAL:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::DECIMAL;
|
||||
break;
|
||||
case SQL_NUMERIC:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::NUMERIC;
|
||||
break;
|
||||
case SQL_BIT:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::BOOLEAN;
|
||||
break;
|
||||
case SQL_TINYINT:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::TINYINT;
|
||||
break;
|
||||
case SQL_SMALLINT:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::SMALLINT;
|
||||
break;
|
||||
case SQL_INTEGER:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::INTEGER;
|
||||
break;
|
||||
case SQL_BIGINT:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::BIGINT;
|
||||
break;
|
||||
case SQL_REAL:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::REAL;
|
||||
break;
|
||||
case SQL_FLOAT:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::FLOAT;
|
||||
break;
|
||||
case SQL_DOUBLE:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::DOUBLE;
|
||||
break;
|
||||
case SQL_BINARY:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::BINARY;
|
||||
break;
|
||||
case SQL_VARBINARY:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::VARBINARY;
|
||||
break;
|
||||
case SQL_LONGVARBINARY:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::LONGVARBINARY;
|
||||
break;
|
||||
case SQL_DATE:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::DATE;
|
||||
break;
|
||||
case SQL_TIME:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::TIME;
|
||||
break;
|
||||
case SQL_TIMESTAMP:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::TIMESTAMP;
|
||||
break;
|
||||
case SQL_TYPE_DATE:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::DATE;
|
||||
break;
|
||||
case SQL_TYPE_TIME:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::TIME;
|
||||
break;
|
||||
case SQL_TYPE_TIMESTAMP:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::TIMESTAMP;
|
||||
break;
|
||||
default:
|
||||
self::$typeMap[$odbctypename] = CreoleTypes::OTHER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@odbc_free_result($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (!self::$typeMap)
|
||||
self::loadTypeMap();
|
||||
|
||||
$t = strtoupper($nativeType);
|
||||
|
||||
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::$typeMap)
|
||||
self::loadTypeMap();
|
||||
|
||||
if (self::$reverseMap === null) {
|
||||
self::$reverseMap = array_flip(self::$typeMap);
|
||||
}
|
||||
return @self::$reverseMap[$creoleType];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
|
||||
|
||||
Creole ODBC Bridge Driver
|
||||
=========================
|
||||
|
||||
|
||||
I. Overview
|
||||
-----------
|
||||
|
||||
In the text below, the word "driver" can get somewhat muddled since there are
|
||||
two libraries concerned here (Creole & ODBC). So, we'll use the term "bridge
|
||||
driver" to refer to Creole's ODBC bridge driver, and "ODBC driver" to refer to
|
||||
an ODBC database driver.
|
||||
|
||||
The Creole ODBC Bridge driver provides a solution for databases which
|
||||
currently have no PHP-native interface. It is currently in an experimental
|
||||
stage of development. It has been tested with two ODBC drivers (Sequiter's
|
||||
CodeBase ODBC driver and the MySQL ODBC driver (as a baseline test)). To
|
||||
use any other ODBC drivers you may need to write your own ODBCAdapter-derived
|
||||
class (see below).
|
||||
|
||||
|
||||
II. ODBCAdapter
|
||||
---------------
|
||||
|
||||
Because ODBC itself is a database abstraction library, the bridge driver needed
|
||||
a way of hiding ODBC driver-specific behavior. The solution to this was to
|
||||
create an adapter layer (akin to how the Propel runtime engine works). Think of
|
||||
it as a sub-driver for the bridge driver. Any ODBC driver-specific behavior is
|
||||
handled by an ODBCAdapter-derived class. To use a specific adapter class, you
|
||||
specify its name via a parameter in the connection string:
|
||||
|
||||
odbc://localhost/DSN=CodeBase;?adapter=CodeBase
|
||||
|
||||
The string above will load the following file as the adapter to use with the
|
||||
bridge driver: creole/drivers/odbc/adapters/CodeBaseAdapter.php
|
||||
|
||||
Some ODBC drivers are limited in support for various Creole features. The
|
||||
ODBCAdapter also provides a method for emulation of some of these missing
|
||||
features:
|
||||
|
||||
-The emulatePrepareStmt() method provides a switch for enabling prepared
|
||||
statement emulation for drivers that do not support (or have trouble with)
|
||||
prepared statements. This emulation is disabled by default.
|
||||
|
||||
-The hasLimitOffset() method provides a switch for enabling LIMIT/OFFSET
|
||||
emulation for drivers that do not support this. This emulation is enabled
|
||||
by default. The LIMIT/OFFSET emulation was borrowed from the MSSQL Creole
|
||||
driver.
|
||||
|
||||
-The createResultSet() method provides a switch for enabling cached
|
||||
result sets. To enable this feature, return an instance of
|
||||
ODBCCachedResultSet in the createResultSet() method of your ODBCAdapter-
|
||||
derived class. This can be useful as a workaround for ODBC drivers which
|
||||
lack support for record count retrieval, reverse/absolute cursor
|
||||
scrolling, etc. In most cases, result rows are cached on-demand. So if
|
||||
you only read the first couple rows of a result, then only those rows will
|
||||
be cached.
|
||||
|
||||
-The getIdGenerator() method provides a switch for enabling sequence
|
||||
emulation. This feature is enabled by default in ODBCAdapter and is
|
||||
implemented in the ODBCIdGenerator class. The emulation code was inspired
|
||||
by the PEAR::DB nextID() method. If your database supports sequences or
|
||||
autoincrement natively, you can return your own IdGenerator-derived class
|
||||
instead. Check out some of the other Creole drivers for IdGenerator
|
||||
examples.
|
||||
|
||||
|
||||
III. Incomplete Features
|
||||
------------------------
|
||||
|
||||
-The database metadata classes are not fully tested/complete. Specifically,
|
||||
the ODBCDatabaseInfo class does not currently set the database name. There
|
||||
may be other problems as well.
|
||||
|
||||
-The Creole CallableStatement class (stored procedures) is not currently
|
||||
implemented. No immediate plans to do this in the future, but it looks
|
||||
feasible.
|
||||
|
||||
|
||||
IV. Known Issues
|
||||
----------------
|
||||
|
||||
This driver was developed using the PHP v5.0 final build. During the course
|
||||
of testing I uncovered several bugs in the php_odbc module. I submitted
|
||||
patches for these bugs, but have not yet received word that they were
|
||||
committed (they were just submitted this morning). If you want more details
|
||||
on the problems I encountered or would like a copy of the patches, please
|
||||
e-mail me (dlawson@masterytech.com).
|
||||
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: CodeBaseAdapter.php,v 1.3 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/drivers/odbc/adapters/ODBCAdapter.php';
|
||||
|
||||
/**
|
||||
* CodeBase driver-specific behavior.
|
||||
*
|
||||
* This adapter is for Sequiter's CodeBaseSQL product. It is a dBase ODBC
|
||||
* driver. The driver only supports forward-only cursor scrolling so this
|
||||
* adapter causes the ODBCCachedResultSet to be used.
|
||||
*
|
||||
* A couple other quirks exist:
|
||||
*
|
||||
* 1) Cannot get blobs to work correctly. If I try writing one to a
|
||||
* LONGVARBINARY typed field, only the first few bytes are written.
|
||||
* This will cause the ResultSetTest::testGetBlob() test case to fail
|
||||
* when running tests for the driver.
|
||||
*
|
||||
* 2) For some reason the character count is off for the
|
||||
* ResultSetTest::testSetClob() test case _only_ when running from the
|
||||
* command line. If I run the same test through a web server it works fine.
|
||||
* Looks like it has something to do with line endings in Windows. The
|
||||
* difference in file sizes is 9803 vs 10090.
|
||||
*
|
||||
* 3) Setting a clob field to null writes a space to the field in the table.
|
||||
* This causes the PreparedStatementTest::testSetNull() test case to fail
|
||||
* when running tests for the driver.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class CodeBaseAdapter extends ODBCAdapter
|
||||
{
|
||||
/**
|
||||
* @see ODBCAdapter::createResultSet()
|
||||
*/
|
||||
public function preservesColumnCase()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ODBCAdapter::createResultSet()
|
||||
*/
|
||||
public function createResultSet($conn, $odbcresult, $fetchmode)
|
||||
{
|
||||
require_once 'creole/drivers/odbc/ODBCResultSet.php';
|
||||
return new ODBCResultSet($conn, $odbcresult, $fetchmode, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: MySQLAdapter.php,v 1.1 2004/07/27 23:08:30 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/drivers/odbc/ODBCCachedResultSet.php';
|
||||
require_once 'creole/drivers/odbc/ODBCResultSet.php';
|
||||
require_once 'creole/drivers/odbc/adapters/ODBCAdapter.php';
|
||||
|
||||
/**
|
||||
* Implements MySQL driver-specific behavior.
|
||||
*
|
||||
* Obviously it would be much more efficient to simply use the Creole
|
||||
* MySQL driver. This adapter was created for the sole purpose of testing
|
||||
* the ODBC driver.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class MySQLAdapter extends ODBCAdapter
|
||||
{
|
||||
/**
|
||||
* @see ODBCAdapter::hasLimitOffset()
|
||||
*/
|
||||
public function hasLimitOffset()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ODBCAdapter::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ( $limit > 0 ) {
|
||||
$sql .= " LIMIT " . ($offset > 0 ? $offset . ", " : "") . $limit;
|
||||
} else if ( $offset > 0 ) {
|
||||
$sql .= " LIMIT " . $offset . ", 18446744073709551615";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ODBCAdapter::escape()
|
||||
*/
|
||||
public function escape($str)
|
||||
{
|
||||
return addslashes($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ODBCAdapter::createResultSet()
|
||||
*/
|
||||
public function createResultSet($conn, $odbcresult, $fetchmode)
|
||||
{
|
||||
// return new ODBCCachedResultSet($conn, $odbcresult, $fetchmode, true);
|
||||
return new ODBCResultSet($conn, $odbcresult, $fetchmode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCAdapter.php,v 1.3 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default class for ODBC driver-specific behavior.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.odbc
|
||||
*/
|
||||
class ODBCAdapter
|
||||
{
|
||||
/**
|
||||
* Returns true if column case is preserved in the database when a table
|
||||
* is first created. Returns false if table does not preserve case (i.e.
|
||||
* ProductID => PRODUCTID).
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function preservesColumnCase()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if prepared statements should be emulated. This
|
||||
* might be useful if your driver does not support (or has trouble with)
|
||||
* prepared statements.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function emulatePrepareStmt()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if ODBC driver supports LIMIT/OFFSET via SQL.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasLimitOffset()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreparedStatementCommon::escape()
|
||||
*/
|
||||
public function escape($str)
|
||||
{
|
||||
// use this instead of magic_quotes_sybase + addslashes(),
|
||||
// just in case multiple RDBMS being used at the same time
|
||||
return str_replace("'", "''", $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the default resultset.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function createResultSet($conn, $odbcresult, $fetchmode)
|
||||
{
|
||||
require_once 'creole/drivers/odbc/ODBCResultSet.php';
|
||||
return new ODBCResultSet($conn, $odbcresult, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default ODBCIdGenerator for emulating sequences.
|
||||
*
|
||||
* @return ODBCIdGenerator
|
||||
*/
|
||||
public function getIdGenerator($conn)
|
||||
{
|
||||
require_once 'creole/drivers/odbc/ODBCIdGenerator.php';
|
||||
return new ODBCIdGenerator($conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if driver support transactions.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function supportsTransactions()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCDatabaseInfo.php,v 1.2 2006/01/17 19:44:39 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';
|
||||
|
||||
/**
|
||||
* ODBC implementation of DatabaseInfo.
|
||||
*
|
||||
* @todo Still need a way to obtain the database name. Not sure how to do this yet.
|
||||
* @todo This might need to be an {@link ODBCAdapter} method.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.2 $
|
||||
* @package creole.drivers.odbc.metadata
|
||||
*/
|
||||
class ODBCDatabaseInfo extends DatabaseInfo {
|
||||
|
||||
/**
|
||||
* @see DatabaseInfo::initTables()
|
||||
*/
|
||||
protected function initTables()
|
||||
{
|
||||
include_once 'creole/drivers/odbc/metadata/ODBCTableInfo.php';
|
||||
|
||||
$result = @odbc_tables($this->conn->getResource());
|
||||
|
||||
if (!$result)
|
||||
throw new SQLException('Could not list tables', $this->conn->nativeError());
|
||||
|
||||
while (odbc_fetch_row($result))
|
||||
{
|
||||
$tablename = strtoupper(odbc_result($result, 'TABLE_NAME'));
|
||||
$this->tables[$tablename] = new ODBCTableInfo($this, $tablename);
|
||||
}
|
||||
|
||||
@odbc_free_result($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function initSequences()
|
||||
{
|
||||
// Not sure how this is used yet.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: ODBCTableInfo.php,v 1.2 2006/01/17 19:44:39 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/TableInfo.php';
|
||||
|
||||
/**
|
||||
* ODBC implementation of TableInfo.
|
||||
*
|
||||
* @author Dave Lawson <dlawson@masterytech.com>
|
||||
* @version $Revision: 1.2 $
|
||||
* @package creole.drivers.odbc.metadata
|
||||
*/
|
||||
class ODBCTableInfo extends TableInfo {
|
||||
|
||||
/**
|
||||
* @see TableInfo::initColumns()
|
||||
*/
|
||||
protected function initColumns()
|
||||
{
|
||||
include_once 'creole/metadata/ColumnInfo.php';
|
||||
include_once 'creole/drivers/odbc/ODBCTypes.php';
|
||||
|
||||
ODBCTypes::loadTypeMap($this->conn);
|
||||
|
||||
$result = @odbc_columns($this->conn->getResource(), $this->dbname, '', $this->name);
|
||||
|
||||
if (!$result)
|
||||
throw new SQLException('Could not get column names', $this->conn->nativeError());
|
||||
|
||||
while (odbc_fetch_row($result))
|
||||
{
|
||||
$name = odbc_result($result, 'COLUMN_NAME');
|
||||
$type = odbc_result($result, 'TYPE_NAME');
|
||||
$length = odbc_result($result, 'LENGTH');
|
||||
$is_nullable = odbc_result($result, 'NULLABLE');
|
||||
$default = '';
|
||||
$precision = odbc_result($result, 'PRECISION');
|
||||
$scale = odbc_result($result, 'SCALE');
|
||||
$this->columns[$name] = new ColumnInfo($this, $name, ODBCTypes::getType($type), $type, $length, $precision, $scale, $is_nullable, $default);
|
||||
}
|
||||
|
||||
@odbc_free_result($result);
|
||||
|
||||
$this->colsLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableInfo::initPrimaryKey()
|
||||
*/
|
||||
protected function initPrimaryKey()
|
||||
{
|
||||
include_once 'creole/metadata/PrimaryKeyInfo.php';
|
||||
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
|
||||
$result = @odbc_primarykeys($this->conn->getResource(), $this->dbname, '', $this->name);
|
||||
|
||||
while (odbc_fetch_row($result))
|
||||
{
|
||||
$name = odbc_result($result, 'COLUMN_NAME');
|
||||
|
||||
if (!isset($this->primaryKey))
|
||||
$this->primaryKey = new PrimaryKeyInfo($name);
|
||||
|
||||
$this->primaryKey->addColumn($this->columns[$name]);
|
||||
}
|
||||
|
||||
@odbc_free_result($result);
|
||||
|
||||
$this->pkLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableInfo::initIndexes()
|
||||
*/
|
||||
protected function initIndexes()
|
||||
{
|
||||
// Not sure if this can be implemented in a driver-independent way.
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableInfo::initForeignKeys()
|
||||
*/
|
||||
protected function initForeignKeys()
|
||||
{
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
|
||||
$result = @odbc_foreignkeys($this->conn->getResource(), '', '', '', $this->dbname, '', $this->name);
|
||||
|
||||
while (odbc_fetch_row($result))
|
||||
{
|
||||
$name = odbc_result($result, 'COLUMN_NAME');
|
||||
$ftbl = odbc_result($result, 'FKTABLE_NAME');
|
||||
$fcol = odbc_result($result, 'FKCOLUMN_NAME');
|
||||
|
||||
if (!isset($this->foreignKeys[$name]))
|
||||
{
|
||||
$this->foreignKeys[$name] = new ForeignKeyInfo($name);
|
||||
|
||||
if (($foreignTable = $this->database->getTable($ftbl)) === null)
|
||||
{
|
||||
$foreignTable = new TableInfo($ltbl);
|
||||
$this->database->addTable($foreignTable);
|
||||
}
|
||||
|
||||
if (($foreignCol = $foreignTable->getColumn($name)) === null)
|
||||
{
|
||||
$foreignCol = new ColumnInfo($foreignTable, $name);
|
||||
$foreignTable->addColumn($foreignCol);
|
||||
}
|
||||
|
||||
$this->foreignKeys[$name]->addReference($this->columns[$name], $foreignCol);
|
||||
}
|
||||
}
|
||||
|
||||
@odbc_free_result($result);
|
||||
|
||||
$this->fksLoaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,393 +0,0 @@
|
|||
<?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' ];
|
||||
$db = $dsninfo[ 'database' ];
|
||||
|
||||
$connect_function = ( $persistent )
|
||||
? 'oci_pconnect'
|
||||
: 'oci_connect';
|
||||
|
||||
$encoding = !empty($dsninfo['encoding']) ? $dsninfo['encoding'] : null;
|
||||
|
||||
@ini_set( 'track_errors', true );
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,424 +0,0 @@
|
|||
<?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] = '';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
<?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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?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 {
|
||||
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<?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::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 = strtolower($nativeType);
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
<?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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,273 +0,0 @@
|
|||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLConnection.php,v 1.21 2005/08/03 17:56:22 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/Connection.php';
|
||||
require_once 'creole/common/ConnectionCommon.php';
|
||||
include_once 'creole/drivers/pgsql/PgSQLResultSet.php';
|
||||
|
||||
/**
|
||||
* PgSQL implementation of Connection.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org> (Creole)
|
||||
* @author Stig Bakken <ssb@fast.no> (PEAR::DB)
|
||||
* @author Lukas Smith (PEAR::MDB)
|
||||
* @version $Revision: 1.21 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLConnection extends ConnectionCommon implements Connection {
|
||||
|
||||
/**
|
||||
* Affected Rows of last executed query.
|
||||
* Postgres needs this for getUpdateCount()
|
||||
* We used to store the entire result set
|
||||
* instead but that can be a large dataset.
|
||||
* @var int
|
||||
*/
|
||||
private $result_affected_rows;
|
||||
|
||||
/**
|
||||
* Connect to a database and log in as the specified user.
|
||||
*
|
||||
* @param array $dsn The datasource hash.
|
||||
* @param $flags Any connection flags.
|
||||
* @access public
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
global $php_errormsg;
|
||||
|
||||
if (!extension_loaded('pgsql')) {
|
||||
throw new SQLException('pgsql extension not loaded');
|
||||
}
|
||||
|
||||
$this->dsn = $dsninfo;
|
||||
$this->flags = $flags;
|
||||
|
||||
$persistent = ($flags & Creole::PERSISTENT === Creole::PERSISTENT);
|
||||
|
||||
$protocol = (isset($dsninfo['protocol'])) ? $dsninfo['protocol'] : 'tcp';
|
||||
$connstr = '';
|
||||
|
||||
if ($protocol == 'tcp') {
|
||||
if (!empty($dsninfo['hostspec'])) {
|
||||
$connstr = 'host=' . $dsninfo['hostspec'];
|
||||
}
|
||||
if (!empty($dsninfo['port'])) {
|
||||
$connstr .= ' port=' . $dsninfo['port'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($dsninfo['database'])) {
|
||||
$connstr .= ' dbname=\'' . addslashes($dsninfo['database']) . '\'';
|
||||
}
|
||||
if (!empty($dsninfo['username'])) {
|
||||
$connstr .= ' user=\'' . addslashes($dsninfo['username']) . '\'';
|
||||
}
|
||||
if (!empty($dsninfo['password'])) {
|
||||
$connstr .= ' password=\'' . addslashes($dsninfo['password']) . '\'';
|
||||
}
|
||||
if (!empty($dsninfo['options'])) {
|
||||
$connstr .= ' options=' . $dsninfo['options'];
|
||||
}
|
||||
if (!empty($dsninfo['tty'])) {
|
||||
$connstr .= ' tty=' . $dsninfo['tty'];
|
||||
}
|
||||
|
||||
if ($persistent) {
|
||||
$conn = @pg_pconnect($connstr);
|
||||
} else {
|
||||
$conn = @pg_connect($connstr);
|
||||
}
|
||||
|
||||
if (!$conn) {
|
||||
// hide the password from connstr
|
||||
$cleanconnstr = preg_replace('/password=\'.*?\'($|\s)/', 'password=\'*********\'', $connstr);
|
||||
throw new SQLException('Could not connect', $php_errormsg, $cleanconnstr);
|
||||
}
|
||||
|
||||
$this->dblink = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ( $limit > 0 ) {
|
||||
$sql .= " LIMIT ".$limit;
|
||||
}
|
||||
if ( $offset > 0 ) {
|
||||
$sql .= " OFFSET ".$offset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::disconnect()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
$ret = @pg_close($this->dblink);
|
||||
$this->result_affected_rows = null;
|
||||
$this->dblink = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::simpleQuery()
|
||||
*/
|
||||
function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
$result = @pg_query($this->dblink, $sql);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute query', pg_last_error($this->dblink), $sql);
|
||||
}
|
||||
$this->result_affected_rows = (int) @pg_affected_rows($result);
|
||||
|
||||
return new PgSQLResultSet($this, $result, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::simpleUpdate()
|
||||
*/
|
||||
function executeUpdate($sql)
|
||||
{
|
||||
$result = @pg_query($this->dblink, $sql);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute update', pg_last_error($this->dblink), $sql);
|
||||
}
|
||||
$this->result_affected_rows = (int) @pg_affected_rows($result);
|
||||
|
||||
return $this->result_affected_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
$result = @pg_query($this->dblink, "BEGIN");
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not begin transaction', pg_last_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
$result = @pg_query($this->dblink, "COMMIT");
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not commit transaction', pg_last_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
$result = @pg_query($this->dblink, "ROLLBACK");
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not rollback transaction', pg_last_error($this->dblink));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of rows affected by the data manipulation
|
||||
* query.
|
||||
* @see Statement::getUpdateCount()
|
||||
* @return int Number of rows affected by the last query.
|
||||
*/
|
||||
function getUpdateCount()
|
||||
{
|
||||
if ( $this->result_affected_rows === null ) {
|
||||
throw new SQLException('getUpdateCount called before any sql queries were executed');
|
||||
}
|
||||
return $this->result_affected_rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
require_once 'creole/drivers/pgsql/metadata/PgSQLDatabaseInfo.php';
|
||||
return new PgSQLDatabaseInfo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
require_once 'creole/drivers/pgsql/PgSQLIdGenerator.php';
|
||||
return new PgSQLIdGenerator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
require_once 'creole/drivers/pgsql/PgSQLPreparedStatement.php';
|
||||
return new PgSQLPreparedStatement($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareCall()
|
||||
*/
|
||||
public function prepareCall($sql) {
|
||||
throw new SQLException('PostgreSQL does not support stored procedures.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
require_once 'creole/drivers/pgsql/PgSQLStatement.php';
|
||||
return new PgSQLStatement($this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLIdGenerator.php,v 1.5 2004/03/19 14:19: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/IdGenerator.php';
|
||||
|
||||
/**
|
||||
* PostgreSQL IdGenerator implemenation.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.5 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLIdGenerator 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 nextval('" . pg_escape_string ( $name ) . "')", ResultSet::FETCHMODE_NUM);
|
||||
$rs->next();
|
||||
return $rs->getInt(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLPreparedStatement.php,v 1.14 2005/04/16 18:55:28 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/PreparedStatement.php';
|
||||
require_once 'creole/common/PreparedStatementCommon.php';
|
||||
|
||||
/**
|
||||
* PgSQL subclass for prepared statements.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.14 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLPreparedStatement extends PreparedStatementCommon implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* Quotes string using native pgsql function (pg_escape_string).
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function escape($str)
|
||||
{
|
||||
return pg_escape_string($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function to turn multi-dim array into str representation.
|
||||
* @param array $arr
|
||||
* @return string Array in pgsql-friendly string notation: {val1, val2} or {{sub1,sub2}, {sub3, sub4}}
|
||||
*/
|
||||
private function arrayToStr($arr)
|
||||
{
|
||||
$parts = array();
|
||||
foreach((array)$arr as $el) {
|
||||
if (is_array($el)) {
|
||||
$parts[] = $this->arrayToStr($el);
|
||||
} else {
|
||||
if (is_string($el)) {
|
||||
$parts[] = '"' . $this->escape($el) . '"';
|
||||
} else {
|
||||
$parts[] = $el;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '{' . implode(',', $parts) . '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an array.
|
||||
* Unless a driver-specific method is used, this means simply serializing
|
||||
* the passed parameter and storing it as a string.
|
||||
* @param int $paramIndex
|
||||
* @param array $value
|
||||
* @return void
|
||||
* @see PreparedStatement::setArray()
|
||||
*/
|
||||
function setArray($paramIndex, $value)
|
||||
{
|
||||
if( $paramIndex > $this->positionsCount || $paramIndex < 1) {
|
||||
throw new SQLException('Cannot bind to invalid param index: '.$paramIndex);
|
||||
}
|
||||
if ($value === null)
|
||||
$this->setNull($paramIndex);
|
||||
else
|
||||
$this->boundInVars[$paramIndex] = "'" . $this->arrayToStr($value) . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* For setting value of Postgres BOOLEAN column.
|
||||
* @param int $paramIndex
|
||||
* @param boolean $value
|
||||
* @return void
|
||||
*/
|
||||
function setBoolean($paramIndex, $value)
|
||||
{
|
||||
if( $paramIndex > $this->positionsCount || $paramIndex < 1) {
|
||||
throw new SQLException('Cannot bind to invalid param index: '.$paramIndex);
|
||||
}
|
||||
if ($value === null)
|
||||
$this->setNull($paramIndex);
|
||||
else
|
||||
$this->boundInVars[$paramIndex] = ($value ? "'t'" : "'f'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies sqlite_udf_encode_binary() to ensure that binary contents will be handled correctly by sqlite.
|
||||
* @param int $paramIndex
|
||||
* @param mixed $blob Blob object or string containing data.
|
||||
* @return void
|
||||
*/
|
||||
function setBlob($paramIndex, $blob)
|
||||
{
|
||||
if ($blob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
// they took magic __toString() out of PHP5.0.0; this sucks
|
||||
if (is_object($blob)) {
|
||||
$blob = $blob->__toString();
|
||||
}
|
||||
$this->boundInVars[$paramIndex] = "'" . pg_escape_bytea( $blob ) . "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paramIndex
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
function setTime($paramIndex, $value)
|
||||
{
|
||||
if ($value === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
if ( is_numeric ( $value ) ) {
|
||||
$value = date ( "H:i:s O", $value );
|
||||
} elseif ( is_object ( $value ) ) {
|
||||
$value = date ( "H:i:s O", $value->getTime ( ) );
|
||||
}
|
||||
$this->boundInVars [ $paramIndex ] = "'" . $this->escape ( $value ) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 O', $value);
|
||||
elseif (is_object($value)) $value = date("Y-m-d H:i:s O", $value->getTime());
|
||||
$this->boundInVars[$paramIndex] = "'".$this->escape($value)."'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLResultSet.php,v 1.31 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';
|
||||
|
||||
/**
|
||||
* PostgreSQL implementation of ResultSet.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.31 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLResultSet extends ResultSetCommon implements ResultSet {
|
||||
|
||||
|
||||
/**
|
||||
* Gets optimized PgSQLResultSetIterator.
|
||||
* @return PgSQLResultSetIterator
|
||||
*/
|
||||
/*
|
||||
public function getIterator()
|
||||
{
|
||||
require_once 'creole/drivers/pgsql/PgSQLResultSetIterator.php';
|
||||
return new PgSQLResultSetIterator($this);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Postgres doesn't actually move the db pointer. The specific row
|
||||
* is fetched by call to pg_fetch_array() rather than by a seek and
|
||||
* then an unspecified pg_fetch_array() call.
|
||||
*
|
||||
* The only side-effect of this situation is that we don't really know
|
||||
* if the seek will fail or succeed until we have called next(). This
|
||||
* behavior is acceptible - and explicitly documented in
|
||||
* ResultSet::seek() phpdoc.
|
||||
*
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
public function seek($rownum)
|
||||
{
|
||||
if ($rownum < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// PostgreSQL rows start w/ 0, but this works, because we are
|
||||
// looking to move the position _before_ the next desired position
|
||||
$this->cursorPos = $rownum;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
/*
|
||||
$this->fields = @pg_fetch_array($this->result, $this->cursorPos, $this->fetchmode);
|
||||
/*/
|
||||
if (pg_num_rows($this->result) > $this->cursorPos) {
|
||||
$this->fields = @pg_fetch_array($this->result, $this->cursorPos, $this->fetchmode);
|
||||
} else {
|
||||
$this->fields = null;
|
||||
}
|
||||
//*/
|
||||
|
||||
|
||||
if (!$this->fields) {
|
||||
$err = @pg_result_error($this->result);
|
||||
if (!$err) {
|
||||
// We've advanced beyond end of recordset.
|
||||
$this->afterLast();
|
||||
return false;
|
||||
} else {
|
||||
throw new SQLException("Error fetching result", $err);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
*/
|
||||
public function getRecordCount()
|
||||
{
|
||||
$rows = @pg_num_rows($this->result);
|
||||
if ($rows === null) {
|
||||
throw new SQLException("Error fetching num rows", pg_result_error($this->result));
|
||||
}
|
||||
return (int) $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::close()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->fields = array();
|
||||
@pg_free_result($this->result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Postgres string representation of array into native PHP array.
|
||||
* @param string $str Postgres string array rep: {1223, 2343} or {{"welcome", "home"}, {"test2", ""}}
|
||||
* @return array
|
||||
*/
|
||||
private function strToArray($str)
|
||||
{
|
||||
$str = substr($str, 1, -1); // remove { }
|
||||
$res = array();
|
||||
|
||||
$subarr = array();
|
||||
$in_subarr = 0;
|
||||
|
||||
$toks = explode(',', $str);
|
||||
foreach($toks as $tok) {
|
||||
if ($in_subarr > 0) { // already in sub-array?
|
||||
$subarr[$in_subarr][] = $tok;
|
||||
if ('}' === substr($tok, -1, 1)) { // check to see if we just added last component
|
||||
$res[] = $this->strToArray(implode(',', $subarr[$in_subarr]));
|
||||
$in_subarr--;
|
||||
}
|
||||
} elseif ($tok{0} === '{') { // we're inside a new sub-array
|
||||
if ('}' !== substr($tok, -1, 1)) {
|
||||
$in_subarr++;
|
||||
// if sub-array has more than one element
|
||||
$subarr[$in_subarr] = array();
|
||||
$subarr[$in_subarr][] = $tok;
|
||||
} else {
|
||||
$res[] = $this->strToArray($tok);
|
||||
}
|
||||
} else { // not sub-array
|
||||
$val = trim($tok, '"'); // remove " (surrounding strings)
|
||||
// perform type castng here?
|
||||
$res[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a column as an array.
|
||||
* The value of the column is unserialized & returned as an array.
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1.
|
||||
* @return array
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getArray($column)
|
||||
{
|
||||
if (is_int($column)) { $column--; } // because Java convention is to start at 1
|
||||
if (!array_key_exists($column, $this->fields)) { throw new SQLException("Invalid resultset column: " . (is_int($column) ? $column + 1 : $column)); }
|
||||
if ($this->fields[$column] === null) { return null; }
|
||||
return $this->strToArray($this->fields[$column]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Blob with contents of column value.
|
||||
*
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1 (if ResultSet::FETCHMODE_NUM was used).
|
||||
* @return Blob New Blob with data from column.
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getBlob($column)
|
||||
{
|
||||
if (is_int($column)) { $column--; } // because Java convention is to start at 1
|
||||
if (!array_key_exists($column, $this->fields)) { throw new SQLException("Invalid resultset column: " . (is_int($column) ? $column + 1 : $column)); }
|
||||
if ($this->fields[$column] === null) { return null; }
|
||||
require_once 'creole/util/Blob.php';
|
||||
$b = new Blob();
|
||||
$b->setContents(pg_unescape_bytea($this->fields[$column]));
|
||||
return $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $column Column name (string) or index (int) starting with 1.
|
||||
* @return boolean
|
||||
* @throws SQLException - If the column specified is not a valid key in current field array.
|
||||
*/
|
||||
public function getBoolean($column)
|
||||
{
|
||||
if (is_int($column)) { $column--; } // because Java convention is to start at 1
|
||||
if (!array_key_exists($column, $this->fields)) { throw new SQLException("Invalid resultset column: " . (is_int($column) ? $column + 1 : $column)); }
|
||||
if ($this->fields[$column] === null) { return null; }
|
||||
return ($this->fields[$column] === 't');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLResultSetIterator.php,v 1.1 2004/12/04 05:58:53 gamr 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optimized iterator for PostgreSQL, based off of SQLite iterator.
|
||||
* Testing with SeekableIterator, no idea if it will keep this
|
||||
* functionality or what uses it or even how to use it as yet.
|
||||
*
|
||||
* @author Cameron Brunner <webmaster@animetorrents.com>
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLResultSetIterator implements SeekableIterator, Countable {
|
||||
|
||||
private $result;
|
||||
private $pos = 0;
|
||||
private $fetchmode;
|
||||
private $row_count;
|
||||
private $rs;
|
||||
|
||||
/**
|
||||
* Construct the iterator.
|
||||
* @param PgSQLResultSet $rs
|
||||
*/
|
||||
public function __construct(PgSQLResultSet $rs)
|
||||
{
|
||||
$this->result = $rs->getResource();
|
||||
$this->fetchmode = $rs->getFetchmode();
|
||||
$this->row_count = $rs->getRecordCount();
|
||||
$this->rs = $rs; // This is to address reference count bug: http://creole.phpdb.org/trac/ticket/6
|
||||
}
|
||||
|
||||
/**
|
||||
* This method actually has no effect, since we do not rewind ResultSet for iteration.
|
||||
*/
|
||||
function rewind()
|
||||
{
|
||||
$this->pos = 0;
|
||||
}
|
||||
|
||||
function valid()
|
||||
{
|
||||
return ( $this->pos < $this->row_count );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cursor position. Note that this will not necessarily
|
||||
* be 1 for the first row, since no rewind is performed at beginning
|
||||
* of iteration.
|
||||
* @return int
|
||||
*/
|
||||
function key()
|
||||
{
|
||||
return $this->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row (assoc array) at current cursor pos.
|
||||
* @return array
|
||||
*/
|
||||
function current()
|
||||
{
|
||||
return pg_fetch_array($this->result, $this->pos, $this->fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances internal cursor pos.
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
$this->pos++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cursor to specific value.
|
||||
*/
|
||||
function seek ( $index )
|
||||
{
|
||||
if ( ! is_int ( $index ) ) {
|
||||
throw new InvalidArgumentException ( 'Invalid arguement to seek' );
|
||||
}
|
||||
if ( $index < 0 || $index > $this->row_count ) {
|
||||
throw new OutOfBoundsException ( 'Invalid seek position' );
|
||||
}
|
||||
$this->pos = $index;
|
||||
}
|
||||
|
||||
function count ( ) {
|
||||
return $this->row_count;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLStatement.php,v 1.1 2004/02/19 02:49:42 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';
|
||||
|
||||
/**
|
||||
* PostgreSQL Statement implementation.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLStatement extends StatementCommon implements Statement {
|
||||
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: PgSQLTypes.php,v 1.8 2004/04/09 19:16:05 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';
|
||||
|
||||
/**
|
||||
* PostgreSQL types / type map.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.8 $
|
||||
* @package creole.drivers.pgsql
|
||||
*/
|
||||
class PgSQLTypes extends CreoleTypes {
|
||||
|
||||
/** Map PostgreSQL native types to Creole (JDBC) types. */
|
||||
private static $typeMap = array (
|
||||
"int2" => CreoleTypes::SMALLINT,
|
||||
"int4" => CreoleTypes::INTEGER,
|
||||
"oid" => CreoleTypes::INTEGER,
|
||||
"int8" => CreoleTypes::BIGINT,
|
||||
"cash" => CreoleTypes::DOUBLE,
|
||||
"money" => CreoleTypes::DOUBLE,
|
||||
"numeric" => CreoleTypes::NUMERIC,
|
||||
"float4" => CreoleTypes::REAL,
|
||||
"float8" => CreoleTypes::DOUBLE,
|
||||
"bpchar" => CreoleTypes::CHAR,
|
||||
"char" => CreoleTypes::CHAR,
|
||||
"char2" => CreoleTypes::CHAR,
|
||||
"char4" => CreoleTypes::CHAR,
|
||||
"char8" => CreoleTypes::CHAR,
|
||||
"char16" => CreoleTypes::CHAR,
|
||||
"varchar" => CreoleTypes::VARCHAR,
|
||||
"text" => CreoleTypes::VARCHAR,
|
||||
"name" => CreoleTypes::VARCHAR,
|
||||
"filename" => CreoleTypes::VARCHAR,
|
||||
"bytea" => CreoleTypes::BINARY,
|
||||
"bool" => CreoleTypes::BOOLEAN,
|
||||
"date" => CreoleTypes::DATE,
|
||||
"time" => CreoleTypes::TIME,
|
||||
"abstime" => CreoleTypes::TIMESTAMP,
|
||||
"timestamp" => CreoleTypes::TIMESTAMP,
|
||||
"timestamptz" => CreoleTypes::TIMESTAMP,
|
||||
"_bool" => CreoleTypes::ARR,
|
||||
"_char" => CreoleTypes::ARR,
|
||||
"_int2" => CreoleTypes::ARR,
|
||||
"_int4" => CreoleTypes::ARR,
|
||||
"_text" => CreoleTypes::ARR,
|
||||
"_oid" => CreoleTypes::ARR,
|
||||
"_varchar" => CreoleTypes::ARR,
|
||||
"_int8" => CreoleTypes::ARR,
|
||||
"_float4" => CreoleTypes::ARR,
|
||||
"_float8" => CreoleTypes::ARR,
|
||||
"_abstime" => CreoleTypes::ARR,
|
||||
"_date" => CreoleTypes::ARR,
|
||||
"_time" => CreoleTypes::ARR,
|
||||
"_timestamp" => CreoleTypes::ARR,
|
||||
"_numeric" => CreoleTypes::ARR,
|
||||
"_bytea" => CreoleTypes::ARR,
|
||||
);
|
||||
|
||||
/** Reverse lookup map, created on demand. */
|
||||
private static $reverseMap = null;
|
||||
|
||||
public static function getType($pgsqlType)
|
||||
{
|
||||
$t = strtolower($pgsqlType);
|
||||
if (isset(self::$typeMap[$t])) {
|
||||
return self::$typeMap[$t];
|
||||
} else {
|
||||
return CreoleTypes::OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getNativeType($creoleType)
|
||||
{
|
||||
if (self::$reverseMap === null) {
|
||||
self::$reverseMap = array_flip(self::$typeMap);
|
||||
}
|
||||
return @self::$reverseMap[$creoleType];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLDatabaseInfo.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';
|
||||
|
||||
/**
|
||||
* MySQL implementation of DatabaseInfo.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.11 $
|
||||
* @package creole.drivers.pgsql.metadata
|
||||
*/
|
||||
class PgSQLDatabaseInfo extends DatabaseInfo {
|
||||
|
||||
/**
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function initTables()
|
||||
{
|
||||
include_once 'creole/drivers/pgsql/metadata/PgSQLTableInfo.php';
|
||||
|
||||
// Get Database Version
|
||||
// TODO: www.php.net/pg_version
|
||||
$result = pg_query ($this->conn->getResource(), "SELECT version() as ver");
|
||||
|
||||
if (!$result)
|
||||
{
|
||||
throw new SQLException ("Failed to select database version");
|
||||
} // if (!$result)
|
||||
$row = pg_fetch_assoc ($result, 0);
|
||||
$arrVersion = sscanf ($row['ver'], '%*s %d.%d');
|
||||
$version = sprintf ("%d.%d", $arrVersion[0], $arrVersion[1]);
|
||||
// Clean up
|
||||
$arrVersion = null;
|
||||
$row = null;
|
||||
pg_free_result ($result);
|
||||
$result = null;
|
||||
|
||||
$result = pg_query($this->conn->getResource(), "SELECT c.oid,
|
||||
case when n.nspname='public' then c.relname else n.nspname||'.'||c.relname end as relname
|
||||
FROM pg_class c join pg_namespace n on (c.relnamespace=n.oid)
|
||||
WHERE c.relkind = 'r'
|
||||
AND n.nspname NOT IN ('information_schema','pg_catalog')
|
||||
AND n.nspname NOT LIKE 'pg_temp%'
|
||||
AND n.nspname NOT LIKE 'pg_toast%'
|
||||
ORDER BY relname");
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list tables", pg_last_error($this->dblink));
|
||||
}
|
||||
|
||||
while ($row = pg_fetch_assoc($result)) {
|
||||
$this->tables[strtoupper($row['relname'])] = new PgSQLTableInfo($this, $row['relname'], $version, $row['oid']);
|
||||
}
|
||||
|
||||
$this->tablesLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* PgSQL sequences.
|
||||
*
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function initSequences()
|
||||
{
|
||||
|
||||
$this->sequences = array();
|
||||
|
||||
$result = pg_query($this->conn->getResource(), "SELECT c.oid,
|
||||
case when n.nspname='public' then c.relname else n.nspname||'.'||c.relname end as relname
|
||||
FROM pg_class c join pg_namespace n on (c.relnamespace=n.oid)
|
||||
WHERE c.relkind = 'S'
|
||||
AND n.nspname NOT IN ('information_schema','pg_catalog')
|
||||
AND n.nspname NOT LIKE 'pg_temp%'
|
||||
AND n.nspname NOT LIKE 'pg_toast%'
|
||||
ORDER BY name");
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list sequences", pg_last_error($this->dblink));
|
||||
}
|
||||
|
||||
while ($row = pg_fetch_assoc($result)) {
|
||||
// FIXME -- decide what info we need for sequences & then create a SequenceInfo object (if needed)
|
||||
$obj = new stdClass;
|
||||
$obj->name = $row['relname'];
|
||||
$obj->oid = $row['oid'];
|
||||
$this->sequences[strtoupper($row['relname'])] = $obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,423 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PgSQLTableInfo.php,v 1.31 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/TableInfo.php';
|
||||
|
||||
/**
|
||||
* PgSQL implementation of TableInfo.
|
||||
*
|
||||
* See this Python code by David M. Cook for some good reference on Pgsql metadata
|
||||
* functions:
|
||||
* @link http://www.sandpyt.org/pipermail/sandpyt/2003-March/000008.html
|
||||
*
|
||||
* Here's some more information from postgresql:
|
||||
* @link http://developer.postgresql.org/docs/pgsql/src/backend/catalog/information_schema.sql
|
||||
*
|
||||
* @todo -c Eventually move to supporting only Postgres >= 7.4, which has the information_schema
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.31 $
|
||||
* @package creole.drivers.pgsql.metadata
|
||||
*/
|
||||
class PgSQLTableInfo extends TableInfo {
|
||||
|
||||
/**
|
||||
* Database Version.
|
||||
* @var String
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* Table OID
|
||||
* @var Integer
|
||||
*/
|
||||
private $oid;
|
||||
|
||||
/**
|
||||
* @param string $table The table name.
|
||||
* @param string $database The database name.
|
||||
* @param resource $dblink The db connection resource.
|
||||
*/
|
||||
function __construct(DatabaseInfo $database, $name, $version, $intOID) {
|
||||
parent::__construct ($database, $name);
|
||||
$this->version = $version;
|
||||
$this->oid = $intOID;
|
||||
} // function __construct(DatabaseInfo $database, $name) {
|
||||
|
||||
/** Load the columns for this table */
|
||||
protected function initColumns () {
|
||||
// Include dependencies
|
||||
include_once ('creole/metadata/ColumnInfo.php');
|
||||
include_once ('creole/drivers/pgsql/PgSQLTypes.php');
|
||||
|
||||
// Get the columns, types, etc.
|
||||
// Based on code from pgAdmin3 (http://www.pgadmin.org/)
|
||||
$result = pg_query ($this->conn->getResource(), sprintf ("SELECT
|
||||
att.attname,
|
||||
att.atttypmod,
|
||||
att.atthasdef,
|
||||
att.attnotnull,
|
||||
def.adsrc,
|
||||
CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray,
|
||||
CASE
|
||||
WHEN ty.typname = 'bpchar'
|
||||
THEN 'char'
|
||||
WHEN ty.typname = '_bpchar'
|
||||
THEN '_char'
|
||||
ELSE
|
||||
ty.typname
|
||||
END AS typname,
|
||||
ty.typtype
|
||||
FROM pg_attribute att
|
||||
JOIN pg_type ty ON ty.oid=att.atttypid
|
||||
LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
|
||||
WHERE att.attrelid = %d AND att.attnum > 0
|
||||
AND att.attisdropped IS FALSE
|
||||
ORDER BY att.attnum", $this->oid));
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list fields for table: " . $this->name, pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
while($row = pg_fetch_assoc($result)) {
|
||||
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
// Check to ensure that this column isn't an array data type
|
||||
if (((int) $row['isarray']) === 1)
|
||||
{
|
||||
throw new SQLException (sprintf ("Array datatypes are not currently supported [%s.%s]", $this->name, $row['attname']));
|
||||
} // if (((int) $row['isarray']) === 1)
|
||||
$name = $row['attname'];
|
||||
// If they type is a domain, Process it
|
||||
if (strtolower ($row['typtype']) == 'd')
|
||||
{
|
||||
$arrDomain = $this->processDomain ($row['typname']);
|
||||
$type = $arrDomain['type'];
|
||||
$size = $arrDomain['length'];
|
||||
$precision = $size;
|
||||
$scale = $arrDomain['scale'];
|
||||
$boolHasDefault = (strlen (trim ($row['atthasdef'])) > 0) ? $row['atthasdef'] : $arrDomain['hasdefault'];
|
||||
$default = (strlen (trim ($row['adsrc'])) > 0) ? $row['adsrc'] : $arrDomain['default'];
|
||||
$is_nullable = (strlen (trim ($row['attnotnull'])) > 0) ? $row['attnotnull'] : $arrDomain['notnull'];
|
||||
$is_nullable = (($is_nullable == 't') ? false : true);
|
||||
} // if (strtolower ($row['typtype']) == 'd')
|
||||
else
|
||||
{
|
||||
$type = $row['typname'];
|
||||
$arrLengthPrecision = $this->processLengthScale ($row['atttypmod'], $type);
|
||||
$size = $arrLengthPrecision['length'];
|
||||
$precision = $size;
|
||||
$scale = $arrLengthPrecision['scale'];
|
||||
$boolHasDefault = $row['atthasdef'];
|
||||
$default = $row['adsrc'];
|
||||
$is_nullable = (($row['attnotnull'] == 't') ? false : true);
|
||||
} // else (strtolower ($row['typtype']) == 'd')
|
||||
|
||||
$autoincrement = null;
|
||||
|
||||
// if column has a default
|
||||
if (($boolHasDefault == 't') && (strlen (trim ($default)) > 0))
|
||||
{
|
||||
if (!preg_match('/^nextval\(/', $default))
|
||||
{
|
||||
$strDefault= preg_replace ('/::[\W\D]*/', '', $default);
|
||||
$default = str_replace ("'", '', $strDefault);
|
||||
} // if (!preg_match('/^nextval\(/', $row['atthasdef']))
|
||||
else
|
||||
{
|
||||
$autoincrement = true;
|
||||
$default = null;
|
||||
} // else
|
||||
} // if (($boolHasDefault == 't') && (strlen (trim ($default)) > 0))
|
||||
else
|
||||
{
|
||||
$default = null;
|
||||
} // else (($boolHasDefault == 't') && (strlen (trim ($default)) > 0))
|
||||
|
||||
$this->columns[$name] = new ColumnInfo($this, $name, PgSQLTypes::getType($type), $type, $size, $precision, $scale, $is_nullable, $default, $autoincrement);
|
||||
}
|
||||
|
||||
$this->colsLoaded = true;
|
||||
} // protected function initColumns ()
|
||||
|
||||
private function processLengthScale ($intTypmod, $strName)
|
||||
{
|
||||
// Define the return array
|
||||
$arrRetVal = array ('length'=>null, 'scale'=>null);
|
||||
|
||||
// Some datatypes don't have a Typmod
|
||||
if ($intTypmod == -1)
|
||||
{
|
||||
return $arrRetVal;
|
||||
} // if ($intTypmod == -1)
|
||||
|
||||
// Numeric Datatype?
|
||||
if ($strName == PgSQLTypes::getNativeType (CreoleTypes::NUMERIC))
|
||||
{
|
||||
$intLen = ($intTypmod - 4) >> 16;
|
||||
$intPrec = ($intTypmod - 4) & 0xffff;
|
||||
$intLen = sprintf ("%ld", $intLen);
|
||||
if ($intPrec)
|
||||
{
|
||||
$intPrec = sprintf ("%ld", $intPrec);
|
||||
} // if ($intPrec)
|
||||
$arrRetVal['length'] = $intLen;
|
||||
$arrRetVal['scale'] = $intPrec;
|
||||
} // if ($strName == PgSQLTypes::getNativeType (CreoleTypes::NUMERIC))
|
||||
elseif ($strName == PgSQLTypes::getNativeType (CreoleTypes::TIME) || $strName == 'timetz'
|
||||
|| $strName == PgSQLTypes::getNativeType (CreoleTypes::TIMESTAMP) || $strName == 'timestamptz'
|
||||
|| $strName == 'interval' || $strName == 'bit')
|
||||
{
|
||||
$arrRetVal['length'] = sprintf ("%ld", $intTypmod);
|
||||
} // elseif (TIME, TIMESTAMP, INTERVAL, BIT)
|
||||
else
|
||||
{
|
||||
$arrRetVal['length'] = sprintf ("%ld", ($intTypmod - 4));
|
||||
} // else
|
||||
return $arrRetVal;
|
||||
} // private function processLengthScale ($intTypmod, $strName)
|
||||
|
||||
private function processDomain ($strDomain)
|
||||
{
|
||||
if (strlen (trim ($strDomain)) < 1)
|
||||
{
|
||||
throw new SQLException ("Invalid domain name [" . $strDomain . "]");
|
||||
} // if (strlen (trim ($strDomain)) < 1)
|
||||
$result = pg_query ($this->conn->getResource(), sprintf ("SELECT
|
||||
d.typname as domname,
|
||||
b.typname as basetype,
|
||||
d.typlen,
|
||||
d.typtypmod,
|
||||
d.typnotnull,
|
||||
d.typdefault
|
||||
FROM pg_type d
|
||||
INNER JOIN pg_type b ON b.oid = CASE WHEN d.typndims > 0 then d.typelem ELSE d.typbasetype END
|
||||
WHERE
|
||||
d.typtype = 'd'
|
||||
AND d.typname = '%s'
|
||||
ORDER BY d.typname", $strDomain));
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Query for domain [" . $strDomain . "] failed.", pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
$row = pg_fetch_assoc ($result);
|
||||
if (!$row)
|
||||
{
|
||||
throw new SQLException ("Domain [" . $strDomain . "] not found.");
|
||||
} // if (!$row)
|
||||
$arrDomain = array ();
|
||||
$arrDomain['type'] = $row['basetype'];
|
||||
$arrLengthPrecision = $this->processLengthScale ($row['typtypmod'], $row['basetype']);
|
||||
$arrDomain['length'] = $arrLengthPrecision['length'];
|
||||
$arrDomain['scale'] = $arrLengthPrecision['scale'];
|
||||
$arrDomain['notnull'] = $row['typnotnull'];
|
||||
$arrDomain['default'] = $row['typdefault'];
|
||||
$arrDomain['hasdefault'] = (strlen (trim ($row['typdefault'])) > 0) ? 't' : 'f';
|
||||
|
||||
pg_free_result ($result);
|
||||
return $arrDomain;
|
||||
} // private function processDomain ($strDomain)
|
||||
|
||||
/** Load foreign keys for this table. */
|
||||
protected function initForeignKeys()
|
||||
{
|
||||
include_once 'creole/metadata/ForeignKeyInfo.php';
|
||||
|
||||
$result = pg_query ($this->conn->getResource(), sprintf ("SELECT
|
||||
conname,
|
||||
confupdtype,
|
||||
confdeltype,
|
||||
cl.relname as fktab,
|
||||
a2.attname as fkcol,
|
||||
cr.relname as reftab,
|
||||
a1.attname as refcol
|
||||
FROM pg_constraint ct
|
||||
JOIN pg_class cl ON cl.oid=conrelid
|
||||
JOIN pg_class cr ON cr.oid=confrelid
|
||||
LEFT JOIN pg_catalog.pg_attribute a1 ON a1.attrelid = ct.confrelid
|
||||
LEFT JOIN pg_catalog.pg_attribute a2 ON a2.attrelid = ct.conrelid
|
||||
WHERE
|
||||
contype='f'
|
||||
AND conrelid = %d
|
||||
AND a2.attnum = ct.conkey[1]
|
||||
AND a1.attnum = ct.confkey[1]
|
||||
ORDER BY conname", $this->oid));
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list foreign keys for table: " . $this->name, pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
while($row = pg_fetch_assoc($result)) {
|
||||
$name = $row['conname'];
|
||||
$local_table = $row['fktab'];
|
||||
$local_column = $row['fkcol'];
|
||||
$foreign_table = $row['reftab'];
|
||||
$foreign_column = $row['refcol'];
|
||||
|
||||
// On Update
|
||||
switch ($row['confupdtype']) {
|
||||
case 'c':
|
||||
$onupdate = ForeignKeyInfo::CASCADE; break;
|
||||
case 'd':
|
||||
$onupdate = ForeignKeyInfo::SETDEFAULT; break;
|
||||
case 'n':
|
||||
$onupdate = ForeignKeyInfo::SETNULL; break;
|
||||
case 'r':
|
||||
$onupdate = ForeignKeyInfo::RESTRICT; break;
|
||||
default:
|
||||
case 'a':
|
||||
//NOACTION is the postgresql default
|
||||
$onupdate = ForeignKeyInfo::NONE; break;
|
||||
}
|
||||
// On Delete
|
||||
switch ($row['confdeltype']) {
|
||||
case 'c':
|
||||
$ondelete = ForeignKeyInfo::CASCADE; break;
|
||||
case 'd':
|
||||
$ondelete = ForeignKeyInfo::SETDEFAULT; break;
|
||||
case 'n':
|
||||
$ondelete = ForeignKeyInfo::SETNULL; break;
|
||||
case 'r':
|
||||
$ondelete = ForeignKeyInfo::RESTRICT; break;
|
||||
default:
|
||||
case 'a':
|
||||
//NOACTION is the postgresql default
|
||||
$ondelete = ForeignKeyInfo::NONE; break;
|
||||
}
|
||||
|
||||
|
||||
$foreignTable = $this->database->getTable($foreign_table);
|
||||
$foreignColumn = $foreignTable->getColumn($foreign_column);
|
||||
|
||||
$localTable = $this->database->getTable($local_table);
|
||||
$localColumn = $localTable->getColumn($local_column);
|
||||
|
||||
if (!isset($this->foreignKeys[$name])) {
|
||||
$this->foreignKeys[$name] = new ForeignKeyInfo($name);
|
||||
}
|
||||
$this->foreignKeys[$name]->addReference($localColumn, $foreignColumn, $ondelete, $onupdate);
|
||||
}
|
||||
|
||||
$this->fksLoaded = true;
|
||||
}
|
||||
|
||||
/** Load indexes for this table */
|
||||
protected function initIndexes()
|
||||
{
|
||||
include_once 'creole/metadata/IndexInfo.php';
|
||||
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
|
||||
$result = pg_query ($this->conn->getResource(), sprintf ("SELECT
|
||||
DISTINCT ON(cls.relname)
|
||||
cls.relname as idxname,
|
||||
indkey,
|
||||
indisunique
|
||||
FROM pg_index idx
|
||||
JOIN pg_class cls ON cls.oid=indexrelid
|
||||
WHERE indrelid = %d AND NOT indisprimary
|
||||
ORDER BY cls.relname", $this->oid));
|
||||
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list indexes keys for table: " . $this->name, pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
while($row = pg_fetch_assoc($result)) {
|
||||
$name = $row["idxname"];
|
||||
$unique = ($row["indisunique"] == 't') ? true : false;
|
||||
if (!isset($this->indexes[$name])) {
|
||||
$this->indexes[$name] = new IndexInfo($name, $unique);
|
||||
}
|
||||
$arrColumns = explode (' ', $row['indkey']);
|
||||
foreach ($arrColumns as $intColNum)
|
||||
{
|
||||
$result2 = pg_query ($this->conn->getResource(), sprintf ("SELECT a.attname
|
||||
FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
||||
WHERE c.oid = '%s' AND a.attnum = %d AND NOT a.attisdropped
|
||||
ORDER BY a.attnum", $this->oid, $intColNum));
|
||||
if (!$result2)
|
||||
{
|
||||
throw new SQLException("Could not list indexes keys for table: " . $this->name, pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
$row2 = pg_fetch_assoc($result2);
|
||||
$this->indexes[$name]->addColumn($this->columns[ $row2['attname'] ]);
|
||||
} // foreach ($arrColumns as $intColNum)
|
||||
}
|
||||
|
||||
$this->indexesLoaded = true;
|
||||
}
|
||||
|
||||
/** Loads the primary keys 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
|
||||
|
||||
$result = pg_query($this->conn->getResource(), sprintf ("SELECT
|
||||
DISTINCT ON(cls.relname)
|
||||
cls.relname as idxname,
|
||||
indkey,
|
||||
indisunique
|
||||
FROM pg_index idx
|
||||
JOIN pg_class cls ON cls.oid=indexrelid
|
||||
WHERE indrelid = %s AND indisprimary
|
||||
ORDER BY cls.relname", $this->oid));
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list primary keys for table: " . $this->name, pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
|
||||
// Loop through the returned results, grouping the same key_name together
|
||||
// adding each column for that key.
|
||||
|
||||
while($row = pg_fetch_assoc($result)) {
|
||||
$arrColumns = explode (' ', $row['indkey']);
|
||||
foreach ($arrColumns as $intColNum)
|
||||
{
|
||||
$result2 = pg_query ($this->conn->getResource(), sprintf ("SELECT a.attname
|
||||
FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
||||
WHERE c.oid = '%s' AND a.attnum = %d AND NOT a.attisdropped
|
||||
ORDER BY a.attnum", $this->oid, $intColNum));
|
||||
if (!$result2)
|
||||
{
|
||||
throw new SQLException("Could not list indexes keys for table: " . $this->name, pg_last_error($this->conn->getResource()));
|
||||
}
|
||||
$row2 = pg_fetch_assoc($result2);
|
||||
if (!isset($this->primaryKey)) {
|
||||
$this->primaryKey = new PrimaryKeyInfo($row2['attname']);
|
||||
}
|
||||
$this->primaryKey->addColumn($this->columns[ $row2['attname'] ]);
|
||||
} // foreach ($arrColumns as $intColNum)
|
||||
}
|
||||
$this->pkLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLiteConnection.php,v 1.15 2006/01/17 19:44:41 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/Connection.php';
|
||||
require_once 'creole/common/ConnectionCommon.php';
|
||||
|
||||
/**
|
||||
* SQLite implementation of Connection.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @author Stig Bakken <ssb@fast.no>
|
||||
* @author Lukas Smith
|
||||
* @version $Revision: 1.15 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLiteConnection extends ConnectionCommon implements Connection {
|
||||
|
||||
/**
|
||||
* The case to use for SQLite results.
|
||||
* (0=nochange, 1=upper, 2=lower)
|
||||
* This is set in each call to executeQuery() in order to ensure that different
|
||||
* Connections do not overwrite each other's settings
|
||||
*/
|
||||
private $sqliteAssocCase;
|
||||
|
||||
/**
|
||||
* @see Connection::connect()
|
||||
*/
|
||||
function connect($dsninfo, $flags = 0)
|
||||
{
|
||||
if (!extension_loaded('sqlite')) {
|
||||
throw new SQLException('sqlite extension not loaded');
|
||||
}
|
||||
|
||||
$file = $dsninfo['database'];
|
||||
|
||||
$this->dsn = $dsninfo;
|
||||
$this->flags = $flags;
|
||||
|
||||
$persistent = ($flags & Creole::PERSISTENT === Creole::PERSISTENT);
|
||||
|
||||
if (PHP_VERSION == '5.0.4' || PHP_VERSION == '5.0.5') {
|
||||
$nochange = TRUE;
|
||||
} else {
|
||||
$nochange = !(($flags & Creole::COMPAT_ASSOC_LOWER) === Creole::COMPAT_ASSOC_LOWER);
|
||||
}
|
||||
|
||||
if ($nochange) {
|
||||
$this->sqliteAssocCase = 0;
|
||||
} else {
|
||||
$this->sqliteAssocCase = 2;
|
||||
}
|
||||
|
||||
if ($file === null) {
|
||||
throw new SQLException("No SQLite database specified.");
|
||||
}
|
||||
|
||||
$mode = (isset($dsninfo['mode']) && is_numeric($dsninfo['mode'])) ? $dsninfo['mode'] : 0644;
|
||||
|
||||
if ($file != ':memory:') {
|
||||
if (!file_exists($file)) {
|
||||
touch($file);
|
||||
chmod($file, $mode);
|
||||
if (!file_exists($file)) {
|
||||
throw new SQLException("Unable to create SQLite database.");
|
||||
}
|
||||
}
|
||||
if (!is_file($file)) {
|
||||
throw new SQLException("Unable to open SQLite database: not a valid file.");
|
||||
}
|
||||
if (!is_readable($file)) {
|
||||
throw new SQLException("Unable to read SQLite database.");
|
||||
}
|
||||
}
|
||||
|
||||
$connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open';
|
||||
if (!($conn = @$connect_function($file, $mode, $errmsg) )) {
|
||||
throw new SQLException("Unable to connect to SQLite database", $errmsg);
|
||||
}
|
||||
|
||||
$this->dblink = $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getDatabaseInfo()
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
require_once 'creole/drivers/sqlite/metadata/SQLiteDatabaseInfo.php';
|
||||
return new SQLiteDatabaseInfo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::getIdGenerator()
|
||||
*/
|
||||
public function getIdGenerator()
|
||||
{
|
||||
require_once 'creole/drivers/sqlite/SQLiteIdGenerator.php';
|
||||
return new SQLiteIdGenerator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareStatement()
|
||||
*/
|
||||
public function prepareStatement($sql)
|
||||
{
|
||||
require_once 'creole/drivers/sqlite/SQLitePreparedStatement.php';
|
||||
return new SQLitePreparedStatement($this, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::prepareCall()
|
||||
*/
|
||||
public function prepareCall($sql) {
|
||||
throw new SQLException('SQLite does not support stored procedures using CallableStatement.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::createStatement()
|
||||
*/
|
||||
public function createStatement()
|
||||
{
|
||||
require_once 'creole/drivers/sqlite/SQLiteStatement.php';
|
||||
return new SQLiteStatement($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::close()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
$ret = @sqlite_close($this->dblink);
|
||||
$this->dblink = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::applyLimit()
|
||||
*/
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ( $limit > 0 ) {
|
||||
$sql .= " LIMIT " . $limit . ($offset > 0 ? " OFFSET " . $offset : "");
|
||||
} elseif ( $offset > 0 ) {
|
||||
$sql .= " LIMIT -1 OFFSET " . $offset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeQuery()
|
||||
*/
|
||||
public function executeQuery($sql, $fetchmode = null)
|
||||
{
|
||||
ini_set('sqlite.assoc_case', $this->sqliteAssocCase);
|
||||
$this->lastQuery = $sql;
|
||||
$result = @sqlite_query($this->dblink, $this->lastQuery);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute query', $php_errormsg, $this->lastQuery); //sqlite_error_string(sqlite_last_error($this->dblink))
|
||||
}
|
||||
require_once 'creole/drivers/sqlite/SQLiteResultSet.php';
|
||||
return new SQLiteResultSet($this, $result, $fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Connection::executeUpdate()
|
||||
*/
|
||||
function executeUpdate($sql)
|
||||
{
|
||||
$this->lastQuery = $sql;
|
||||
$result = @sqlite_query($this->dblink, $this->lastQuery);
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not execute update', $php_errormsg, $this->lastQuery); //sqlite_error_string(sqlite_last_error($this->dblink))
|
||||
}
|
||||
return (int) @sqlite_changes($this->dblink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function beginTrans()
|
||||
{
|
||||
$result = @sqlite_query($this->dblink, 'BEGIN');
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not begin transaction', $php_errormsg); //sqlite_error_string(sqlite_last_error($this->dblink))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function commitTrans()
|
||||
{
|
||||
$result = @sqlite_query($this->dblink, 'COMMIT');
|
||||
if (!$result) {
|
||||
throw new SQLException('Can not commit transaction', $php_errormsg); // sqlite_error_string(sqlite_last_error($this->dblink))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back (undo) the current transaction.
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackTrans()
|
||||
{
|
||||
$result = @sqlite_query($this->dblink, 'ROLLBACK');
|
||||
if (!$result) {
|
||||
throw new SQLException('Could not rollback transaction', $php_errormsg); // sqlite_error_string(sqlite_last_error($this->dblink))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of rows affected by the data manipulation
|
||||
* query.
|
||||
*
|
||||
* @return int Number of rows affected by the last query.
|
||||
*/
|
||||
function getUpdateCount()
|
||||
{
|
||||
return (int) @sqlite_changes($this->dblink);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once 'creole/IdGenerator.php';
|
||||
|
||||
/**
|
||||
* SQLite IdGenerator implimenation.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.4 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLiteIdGenerator 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 false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::isAfterInsert()
|
||||
*/
|
||||
public function isAfterInsert()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::getIdMethod()
|
||||
*/
|
||||
public function getIdMethod()
|
||||
{
|
||||
return self::AUTOINCREMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IdGenerator::getId()
|
||||
*/
|
||||
public function getId($unused = null)
|
||||
{
|
||||
return sqlite_last_insert_rowid($this->conn->getResource());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLitePreparedStatement.php,v 1.7 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/PreparedStatement.php';
|
||||
require_once 'creole/common/PreparedStatementCommon.php';
|
||||
|
||||
/**
|
||||
* MySQL subclass for prepared statements.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.7 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLitePreparedStatement extends PreparedStatementCommon implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* Quotes string using native sqlite_escape_string() function.
|
||||
* @see ResultSetCommon::escape()
|
||||
*/
|
||||
protected function escape($str)
|
||||
{
|
||||
return sqlite_escape_string($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies sqlite_udf_encode_binary() to ensure that binary contents will be handled correctly by sqlite.
|
||||
* @see PreparedStatement::setBlob()
|
||||
* @see ResultSet::getBlob()
|
||||
*/
|
||||
function setBlob($paramIndex, $blob)
|
||||
{
|
||||
if ($blob === null) {
|
||||
$this->setNull($paramIndex);
|
||||
} else {
|
||||
// they took magic __toString() out of PHP5.0.0; this sucks
|
||||
if (is_object($blob)) {
|
||||
$blob = $blob->__toString();
|
||||
}
|
||||
$this->boundInVars[$paramIndex] = "'" . sqlite_udf_encode_binary( $blob ) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLiteResultSet.php,v 1.9 2004/11/29 13:41:24 micha 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';
|
||||
|
||||
/**
|
||||
* SQLite implementation of ResultSet class.
|
||||
*
|
||||
* SQLite supports OFFSET / LIMIT natively; this means that no adjustments or checking
|
||||
* are performed. We will assume that if the lmitSQL() operation failed that an
|
||||
* exception was thrown, and that OFFSET/LIMIT will never be emulated for SQLite.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.9 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLiteResultSet extends ResultSetCommon implements ResultSet {
|
||||
|
||||
/**
|
||||
* Gets optimized SQLiteResultSetIterator.
|
||||
* @return SQLiteResultSetIterator
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
require_once 'creole/drivers/sqlite/SQLiteResultSetIterator.php';
|
||||
return new SQLiteResultSetIterator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::seek()
|
||||
*/
|
||||
public function seek($rownum)
|
||||
{
|
||||
// MySQL rows start w/ 0, but this works, because we are
|
||||
// looking to move the position _before_ the next desired position
|
||||
if (!@sqlite_seek($this->result, $rownum)) {
|
||||
return false;
|
||||
}
|
||||
$this->cursorPos = $rownum;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::next()
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
$this->fields = sqlite_fetch_array($this->result, $this->fetchmode); // (ResultSet::FETCHMODE_NUM = SQLITE_NUM, etc.)
|
||||
if (!$this->fields) {
|
||||
$errno = sqlite_last_error($this->conn->getResource());
|
||||
if (!$errno) {
|
||||
// We've advanced beyond end of recordset.
|
||||
$this->afterLast();
|
||||
return false;
|
||||
} else {
|
||||
throw new SQLException("Error fetching result", sqlite_error_string($errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Advance cursor position
|
||||
$this->cursorPos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ResultSet::getRecordCount()
|
||||
*/
|
||||
public function getRecordCount()
|
||||
{
|
||||
$rows = @sqlite_num_rows($this->result);
|
||||
if ($rows === null) {
|
||||
throw new SQLException("Error fetching num rows", sqlite_error_string(sqlite_last_error($this->conn->getResource())));
|
||||
}
|
||||
return (int) $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs sqlite_udf_decode_binary on binary data.
|
||||
* @see ResultSet::getBlob()
|
||||
*/
|
||||
public function getBlob($column)
|
||||
{
|
||||
$idx = (is_int($column) ? $column - 1 : $column);
|
||||
if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); }
|
||||
if ($this->fields[$idx] === null) { return null; }
|
||||
require_once 'creole/util/Blob.php';
|
||||
$b = new Blob();
|
||||
$b->setContents(sqlite_udf_decode_binary($this->fields[$idx]));
|
||||
return $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply empties array as there is no result free method for sqlite.
|
||||
* @see ResultSet::close()
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->fields = array();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLiteResultSetIterator.php,v 1.6 2004/12/03 16:57:54 gamr 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optimized iterator for SQLite.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.6 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLiteResultSetIterator implements Iterator {
|
||||
|
||||
private $result;
|
||||
private $pos = 0;
|
||||
private $fetchmode;
|
||||
private $row_count;
|
||||
|
||||
/**
|
||||
* Construct the iterator.
|
||||
* @param SQLiteResultSet $rs
|
||||
*/
|
||||
public function __construct(SQLiteResultSet $rs)
|
||||
{
|
||||
$this->result = $rs->getResource();
|
||||
$this->fetchmode = $rs->getFetchmode();
|
||||
$this->row_count = $rs->getRecordCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method actually has no effect, since we do not rewind ResultSet for iteration.
|
||||
*/
|
||||
function rewind()
|
||||
{
|
||||
sqlite_rewind($this->result);
|
||||
}
|
||||
|
||||
function valid()
|
||||
{
|
||||
return ( $this->pos < $this->row_count );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cursor position. Note that this will not necessarily
|
||||
* be 1 for the first row, since no rewind is performed at beginning
|
||||
* of iteration.
|
||||
* @return int
|
||||
*/
|
||||
function key()
|
||||
{
|
||||
return $this->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row (assoc array) at current cursor pos.
|
||||
* @return array
|
||||
*/
|
||||
function current()
|
||||
{
|
||||
return sqlite_fetch_array($this->result, $this->fetchmode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances internal cursor pos.
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
$this->pos++;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLiteStatement.php,v 1.1 2004/02/19 02:49:43 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';
|
||||
|
||||
/**
|
||||
* SQLite Statement
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.1 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLiteStatement extends StatementCommon implements Statement {
|
||||
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: SQLiteTypes.php,v 1.3 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';
|
||||
|
||||
/**
|
||||
* MySQL types / type map.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.sqlite
|
||||
*/
|
||||
class SQLiteTypes extends CreoleTypes {
|
||||
|
||||
/**
|
||||
* Map some fake SQLite types CreoleTypes.
|
||||
* SQLite is typeless so this is really only for "hint" / readability
|
||||
* purposes.
|
||||
* @var array
|
||||
*/
|
||||
private static $typeMap = array(
|
||||
'tinyint' => CreoleTypes::TINYINT,
|
||||
'smallint' => CreoleTypes::SMALLINT,
|
||||
'mediumint' => CreoleTypes::SMALLINT,
|
||||
'int' => CreoleTypes::INTEGER,
|
||||
'integer' => CreoleTypes::INTEGER,
|
||||
'bigint' => CreoleTypes::BIGINT,
|
||||
'int24' => CreoleTypes::BIGINT,
|
||||
'real' => CreoleTypes::REAL,
|
||||
'float' => CreoleTypes::FLOAT,
|
||||
'decimal' => CreoleTypes::DECIMAL,
|
||||
'numeric' => CreoleTypes::NUMERIC,
|
||||
'double' => CreoleTypes::DOUBLE,
|
||||
'char' => CreoleTypes::CHAR,
|
||||
'varchar' => CreoleTypes::VARCHAR,
|
||||
'date' => CreoleTypes::DATE,
|
||||
'time' => CreoleTypes::TIME,
|
||||
'year' => CreoleTypes::YEAR,
|
||||
'datetime' => CreoleTypes::TIMESTAMP,
|
||||
'timestamp' => CreoleTypes::TIMESTAMP,
|
||||
'tinyblob' => CreoleTypes::BINARY,
|
||||
'blob' => CreoleTypes::VARBINARY,
|
||||
'mediumblob' => CreoleTypes::VARBINARY,
|
||||
'longblob' => CreoleTypes::VARBINARY,
|
||||
'tinytext' => CreoleTypes::VARCHAR,
|
||||
'mediumtext' => CreoleTypes::LONGVARCHAR,
|
||||
'text' => CreoleTypes::LONGVARCHAR,
|
||||
);
|
||||
|
||||
/** Reverse mapping, created on demand. */
|
||||
private static $reverseMap = null;
|
||||
|
||||
/**
|
||||
* This method returns the generic Creole (JDBC-like) type
|
||||
* when given the native db type. If no match is found then we just
|
||||
* return CreoleTypes::TEXT because SQLite is typeless.
|
||||
* @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 = strtolower($nativeType);
|
||||
if (isset(self::$typeMap[$t])) {
|
||||
return self::$typeMap[$t];
|
||||
} else {
|
||||
return CreoleTypes::TEXT; // because SQLite is typeless
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return a native type that corresponds to the specified
|
||||
* Creole (JDBC-like) type. Remember that this is really only for "hint" purposes
|
||||
* as SQLite is typeless.
|
||||
*
|
||||
* 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];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLiteDatabaseInfo.php,v 1.3 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/metadata/DatabaseInfo.php';
|
||||
|
||||
/**
|
||||
* SQLite implementation of DatabaseInfo.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.3 $
|
||||
* @package creole.drivers.sqlite.metadata
|
||||
*/
|
||||
class SQLiteDatabaseInfo extends DatabaseInfo {
|
||||
|
||||
/**
|
||||
* @throws SQLException
|
||||
* @return void
|
||||
*/
|
||||
protected function initTables()
|
||||
{
|
||||
include_once 'creole/drivers/sqlite/metadata/SQLiteTableInfo.php';
|
||||
|
||||
$sql = "SELECT name FROM sqlite_master WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table' ORDER BY name;";
|
||||
$result = sqlite_query($this->dblink, $sql);
|
||||
|
||||
if (!$result) {
|
||||
throw new SQLException("Could not list tables", sqlite_last_error($this->dblink));
|
||||
}
|
||||
|
||||
while ($row = sqlite_fetch_array($result)) {
|
||||
$this->tables[strtoupper($row[0])] = new SQLiteTableInfo($this, $row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SQLite does not support sequences.
|
||||
*
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected function initSequences()
|
||||
{
|
||||
// throw new SQLException("MySQL does not support sequences natively.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLiteTableInfo.php,v 1.8 2005/10/18 02:27: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/metadata/TableInfo.php';
|
||||
|
||||
/**
|
||||
* MySQL implementation of TableInfo.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.8 $
|
||||
* @package creole.drivers.sqlite.metadata
|
||||
*/
|
||||
class SQLiteTableInfo extends TableInfo {
|
||||
|
||||
/** Loads the columns for this table. */
|
||||
protected function initColumns()
|
||||
{
|
||||
|
||||
include_once 'creole/metadata/ColumnInfo.php';
|
||||
include_once 'creole/metadata/PrimaryKeyInfo.php';
|
||||
include_once 'creole/drivers/sqlite/SQLiteTypes.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 = 'PRAGMA table_info('.$this->name.')';
|
||||
|
||||
$res = sqlite_query($this->conn->getResource(), $sql);
|
||||
|
||||
|
||||
while($row = sqlite_fetch_array($res, SQLITE_ASSOC)) {
|
||||
|
||||
$name = $row['name'];
|
||||
|
||||
$fulltype = $row['type'];
|
||||
$size = null;
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
|
||||
if (preg_match('/^([^\(]+)\(\s*(\d+)\s*,\s*(\d+)\s*\)$/', $fulltype, $matches)) {
|
||||
$type = $matches[1];
|
||||
$precision = $matches[2];
|
||||
$scale = $matches[3]; // aka precision
|
||||
} elseif (preg_match('/^([^\(]+)\(\s*(\d+)\s*\)$/', $fulltype, $matches)) {
|
||||
$type = $matches[1];
|
||||
$size = $matches[2];
|
||||
} else {
|
||||
$type = $fulltype;
|
||||
}
|
||||
|
||||
$not_null = $row['notnull'];
|
||||
$is_nullable = !$not_null;
|
||||
|
||||
$default_val = $row['dflt_value'];
|
||||
|
||||
$this->columns[$name] = new ColumnInfo($this, $name, SQLiteTypes::getType($type), $type, $size, $precision, $scale, $is_nullable, $default_val);
|
||||
|
||||
if (($row['pk'] == 1) || (strtolower($type) == 'integer primary key')) {
|
||||
if ($this->primaryKey === null) {
|
||||
$this->primaryKey = new PrimaryKeyInfo($name);
|
||||
}
|
||||
$this->primaryKey->addColumn($this->columns[ $name ]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->colsLoaded = true;
|
||||
}
|
||||
|
||||
/** Loads the primary key information for this table. */
|
||||
protected function initPrimaryKey()
|
||||
{
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
// keys are loaded by initColumns() in this class.
|
||||
$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();
|
||||
|
||||
$sql = 'PRAGMA index_list('.$this->name.')';
|
||||
$res = sqlite_query($this->conn->getResource(), $sql);
|
||||
|
||||
while($row = sqlite_fetch_array($res, SQLITE_ASSOC)) {
|
||||
$name = $row['name'];
|
||||
$this->indexes[$name] = new IndexInfo($name);
|
||||
|
||||
// get columns for that index
|
||||
$res2 = sqlite_query($this->conn->getResource(), 'PRAGMA index_info('.$name.')');
|
||||
while($row2 = sqlite_fetch_array($res2, SQLITE_ASSOC)) {
|
||||
$colname = $row2['name'];
|
||||
$this->indexes[$name]->addColumn($this->columns[ $colname ]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->indexesLoaded = true;
|
||||
}
|
||||
|
||||
/** Load foreign keys (unsupported in SQLite). */
|
||||
protected function initForeignKeys() {
|
||||
|
||||
// columns have to be loaded first
|
||||
if (!$this->colsLoaded) $this->initColumns();
|
||||
|
||||
// No fkeys in SQLite
|
||||
|
||||
$this->fksLoaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: ColumnInfo.php,v 1.13 2005/02/25 15:47:02 pachanga 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Column.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.13 $
|
||||
* @package creole.metadata
|
||||
*/
|
||||
class ColumnInfo {
|
||||
|
||||
// FIXME
|
||||
// - Currently all member attributes are public. This should be fixed
|
||||
// when PHP's magic __sleep() and __wakeup() functions & serialization support
|
||||
// handles protected/private members. (if ever)
|
||||
|
||||
/** Column name */
|
||||
public $name;
|
||||
|
||||
/** Column Creole type. */
|
||||
public $type;
|
||||
|
||||
/** Column native type */
|
||||
public $nativeType;
|
||||
|
||||
/** Column length */
|
||||
public $size;
|
||||
|
||||
/** Column presision */
|
||||
public $precision;
|
||||
|
||||
/** Column scale (number of digits after decimal ) */
|
||||
public $scale;
|
||||
|
||||
/** Is nullable? */
|
||||
public $isNullable;
|
||||
|
||||
/** Default value */
|
||||
public $defaultValue;
|
||||
|
||||
/** Is autoincrement? */
|
||||
public $isAutoIncrement;
|
||||
|
||||
/** Table */
|
||||
public $table;
|
||||
|
||||
/**
|
||||
* Additional and optional vendor specific information.
|
||||
* @var vendorSpecificInfo
|
||||
*/
|
||||
protected $vendorSpecificInfo = array();
|
||||
|
||||
/**
|
||||
* Construct a new ColumnInfo object.
|
||||
*
|
||||
* @param TableInfo $table The table that owns this column.
|
||||
* @param string $name Column name.
|
||||
* @param int $type Creole type.
|
||||
* @param string $nativeType Native type name.
|
||||
* @param int $size Column length.
|
||||
* @param int $scale Column scale (number of digits after decimal).
|
||||
* @param boolean $is_nullable Whether col is nullable.
|
||||
* @param mixed $default Default value.
|
||||
* @param boolean $is_auto_increment Whether col is of autoIncrement type.
|
||||
*/
|
||||
function __construct(TableInfo
|
||||
$table,
|
||||
$name,
|
||||
$type = null,
|
||||
$nativeType = null,
|
||||
$size = null,
|
||||
$precision=null,
|
||||
$scale = null,
|
||||
$is_nullable = null,
|
||||
$default = null,
|
||||
$is_auto_increment = null,
|
||||
$vendorInfo = array())
|
||||
{
|
||||
$this->table = $table;
|
||||
$this->name = $name;
|
||||
$this->type = $type;
|
||||
$this->nativeType = $nativeType;
|
||||
$this->size = $size;
|
||||
$this->precision = $precision;
|
||||
$this->scale = $scale;
|
||||
$this->isNullable = $is_nullable;
|
||||
$this->defaultValue = $default;
|
||||
$this->isAutoIncrement = $is_auto_increment;
|
||||
$this->vendorSpecificInfo = $vendorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* This "magic" method is invoked upon serialize().
|
||||
* Because the Info class hierarchy is recursive, we must handle
|
||||
* the serialization and unserialization of this object.
|
||||
* @return array The class variables that should be serialized (all must be public!).
|
||||
*/
|
||||
function __sleep()
|
||||
{
|
||||
return array('name', 'type', 'nativeType', 'size', 'precision', 'isNullable', 'defaultValue');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column type.
|
||||
* @return int
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the native type name.
|
||||
* @return string
|
||||
*/
|
||||
public function getNativeType()
|
||||
{
|
||||
return $this->nativeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column size.
|
||||
* @return int
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column precision.
|
||||
* @return int
|
||||
*/
|
||||
public function getPrecision()
|
||||
{
|
||||
return $this->precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column scale.
|
||||
* Scale refers to number of digits after the decimal. Sometimes this is referred
|
||||
* to as precision, but precision is the total number of digits (i.e. length).
|
||||
* @return int
|
||||
*/
|
||||
public function getScale()
|
||||
{
|
||||
return $this->scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is column nullable?
|
||||
* @return boolean
|
||||
*/
|
||||
public function isNullable()
|
||||
{
|
||||
return $this->isNullable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is column of autoincrement type?
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAutoIncrement()
|
||||
{
|
||||
return $this->isAutoIncrement === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vendor specific optional information for this column.
|
||||
* @return array vendorSpecificInfo[]
|
||||
*/
|
||||
public function getVendorSpecificInfo()
|
||||
{
|
||||
return $this->vendorSpecificInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent table.
|
||||
* @return TableInfo
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,206 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: DatabaseInfo.php,v 1.15 2005/11/08 04:24: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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* "Info" metadata class for a database.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.15 $
|
||||
* @package creole.metadata
|
||||
*/
|
||||
abstract class DatabaseInfo {
|
||||
|
||||
protected $tables = array();
|
||||
|
||||
protected $sequences = array();
|
||||
|
||||
/** have tables been loaded */
|
||||
protected $tablesLoaded = false;
|
||||
|
||||
/** have sequences been loaded */
|
||||
protected $seqsLoaded = false;
|
||||
|
||||
/** additional vendor specific information */
|
||||
private $vendorSpecificInfo = array();
|
||||
|
||||
/**
|
||||
* The database Connection.
|
||||
* @var Connection
|
||||
*/
|
||||
protected $conn;
|
||||
|
||||
/** Database name. */
|
||||
protected $dbname;
|
||||
|
||||
/**
|
||||
* Database link
|
||||
* @var resource
|
||||
*/
|
||||
protected $dblink;
|
||||
|
||||
/**
|
||||
* @param Connection $dbh
|
||||
*/
|
||||
public function __construct(Connection $conn, $vendorInfo = array())
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->dblink = $conn->getResource();
|
||||
$dsn = $conn->getDSN();
|
||||
$this->dbname = $dsn['database'];
|
||||
$this->vendorSpecificInfo = $vendorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name of database.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->dbname;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked upon serialize().
|
||||
* Because the Info class hierarchy is recursive, we must handle
|
||||
* the serialization and unserialization of this object.
|
||||
* @return array The class variables that should be serialized (all must be public!).
|
||||
*/
|
||||
function __sleep()
|
||||
{
|
||||
return array('tables','sequences','conn');
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked upon unserialize().
|
||||
* This method re-hydrates the object and restores the recursive hierarchy.
|
||||
*/
|
||||
function __wakeup()
|
||||
{
|
||||
// Re-init vars from serialized connection
|
||||
$this->dbname = $conn->database;
|
||||
$this->dblink = $conn->connection;
|
||||
|
||||
// restore chaining
|
||||
foreach($this->tables as $tbl) {
|
||||
$tbl->database = $this;
|
||||
$tbl->dbname = $this->dbname;
|
||||
$tbl->dblink = $this->dblink;
|
||||
$tbl->schema = $this->schema;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Connection being used.
|
||||
* @return Connection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TableInfo object for specified table name.
|
||||
* @param string $name The name of the table to retrieve.
|
||||
* @return TableInfo
|
||||
* @throws SQLException - if table does not exist in this db.
|
||||
*/
|
||||
public function getTable($name)
|
||||
{
|
||||
if(!$this->tablesLoaded) $this->initTables();
|
||||
if (!isset($this->tables[strtoupper($name)])) {
|
||||
throw new SQLException("Database `".$this->dbname."` has no table `".$name."`");
|
||||
}
|
||||
return $this->tables[ strtoupper($name) ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether database contains specified table.
|
||||
* @param string $name The table name.
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTable($name)
|
||||
{
|
||||
return isset($this->tables[strtoupper($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets array of TableInfo objects.
|
||||
* @return array TableInfo[]
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
if(!$this->tablesLoaded) $this->initTables();
|
||||
return array_values($this->tables); //re-key [numerically]
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table to this db.
|
||||
* Table name is case-insensitive.
|
||||
* @param TableInfo $table
|
||||
*/
|
||||
public function addTable(TableInfo $table)
|
||||
{
|
||||
$this->tables[strtoupper($table->getName())] = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
abstract protected function initTables();
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws SQLException
|
||||
*/
|
||||
abstract protected function initSequences();
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @throws SQLException
|
||||
*/
|
||||
public function isSequence($key)
|
||||
{
|
||||
if(!$this->seqsLoaded) $this->initSequences();
|
||||
return isset($this->sequences[ strtoupper($key) ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets array of ? objects.
|
||||
* @return array ?[]
|
||||
*/
|
||||
public function getSequences()
|
||||
{
|
||||
if(!$this->seqsLoaded) $this->initSequences();
|
||||
return array_values($this->sequences); //re-key [numerically]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vendor specific optional information for this primary key.
|
||||
* @return array vendorSpecificInfo[]
|
||||
*/
|
||||
public function getVendorSpecificInfo()
|
||||
{
|
||||
return $this->vendorSpecificInfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: ForeignKeyInfo.php,v 1.9 2005/08/02 14:42:36 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a foreign key.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.9 $
|
||||
* @package creole.metadata
|
||||
*/
|
||||
class ForeignKeyInfo {
|
||||
|
||||
private $name;
|
||||
private $references = array();
|
||||
|
||||
/**
|
||||
* Additional and optional vendor specific information.
|
||||
* @var vendorSpecificInfo
|
||||
*/
|
||||
protected $vendorSpecificInfo = array();
|
||||
|
||||
|
||||
const NONE = ""; // No "ON [ DELETE | UPDATE]" behaviour specified.
|
||||
const NOACTION = "NO ACTION";
|
||||
const CASCADE = "CASCADE";
|
||||
const RESTRICT = "RESTRICT";
|
||||
const SETDEFAULT = "SET DEFAULT";
|
||||
const SETNULL = "SET NULL";
|
||||
|
||||
/**
|
||||
* @param string $name The name of the foreign key.
|
||||
*/
|
||||
function __construct($name, $vendorInfo = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->vendorSpecificInfo = $vendorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get foreign key name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a foreign-local mapping.
|
||||
* @param ColumnInfo $local
|
||||
* @param ColumnInfo $foreign
|
||||
*/
|
||||
public function addReference(ColumnInfo $local, ColumnInfo $foreign, $onDelete = self::NONE, $onUpdate = self::NONE)
|
||||
{
|
||||
$this->references[] = array($local, $foreign, $onDelete, $onUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local-foreign column mapping.
|
||||
* @return array array( [0] => array([0] => local ColumnInfo object, [1] => foreign ColumnInfo object, [2] => onDelete, [3] => onUpdate) )
|
||||
*/
|
||||
public function getReferences()
|
||||
{
|
||||
return $this->references;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vendor specific optional information for this primary key.
|
||||
* @return array vendorSpecificInfo[]
|
||||
*/
|
||||
public function getVendorSpecificInfo()
|
||||
{
|
||||
return $this->vendorSpecificInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: IndexInfo.php,v 1.7 2005/02/25 15:47:02 pachanga 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents an index.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.7 $
|
||||
* @package creole.metadata
|
||||
*/
|
||||
class IndexInfo {
|
||||
|
||||
/** name of the index */
|
||||
private $name;
|
||||
|
||||
/** columns in this index */
|
||||
private $columns = array();
|
||||
|
||||
/** uniqueness flag */
|
||||
private $isUnique = false;
|
||||
|
||||
/** additional vendor specific information */
|
||||
private $vendorSpecificInfo = array();
|
||||
|
||||
function __construct($name, $isUnique = false, $vendorInfo = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->isUnique = $isUnique;
|
||||
$this->vendorSpecificInfo = $vendorInfo;
|
||||
}
|
||||
|
||||
public function isUnique()
|
||||
{
|
||||
return $this->isUnique;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vendor specific optional information for this index.
|
||||
* @return array vendorSpecificInfo[]
|
||||
*/
|
||||
public function getVendorSpecificInfo()
|
||||
{
|
||||
return $this->vendorSpecificInfo;
|
||||
}
|
||||
|
||||
public function addColumn($column)
|
||||
{
|
||||
$this->columns[] = $column;
|
||||
}
|
||||
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
public function toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: PrimaryKeyInfo.php,v 1.6 2005/02/25 15:47:02 pachanga 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a PrimaryKey
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.6 $
|
||||
* @package creole.metadata
|
||||
*/
|
||||
class PrimaryKeyInfo {
|
||||
|
||||
/** name of the primary key */
|
||||
private $name;
|
||||
|
||||
/** columns in the primary key */
|
||||
private $columns = array();
|
||||
|
||||
/** additional vendor specific information */
|
||||
private $vendorSpecificInfo = array();
|
||||
|
||||
/**
|
||||
* @param string $name The name of the foreign key.
|
||||
*/
|
||||
function __construct($name, $vendorInfo = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->vendorSpecificInfo = $vendorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get foreign key name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Column $column
|
||||
* @return void
|
||||
*/
|
||||
public function addColumn($column)
|
||||
{
|
||||
$this->columns[] = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Column[]
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vendor specific optional information for this primary key.
|
||||
* @return array vendorSpecificInfo[]
|
||||
*/
|
||||
public function getVendorSpecificInfo()
|
||||
{
|
||||
return $this->vendorSpecificInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* $Id: TableInfo.php,v 1.16 2005/10/17 19:05:10 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a table.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.16 $
|
||||
* @package creole.metadata
|
||||
*/
|
||||
abstract class TableInfo {
|
||||
|
||||
protected $name;
|
||||
protected $columns = array();
|
||||
protected $foreignKeys = array();
|
||||
protected $indexes = array();
|
||||
protected $primaryKey;
|
||||
|
||||
protected $pkLoaded = false;
|
||||
protected $fksLoaded = false;
|
||||
protected $indexesLoaded = false;
|
||||
protected $colsLoaded = false;
|
||||
protected $vendorLoaded = false;
|
||||
|
||||
/**
|
||||
* Additional and optional vendor specific information.
|
||||
* @var vendorSpecificInfo
|
||||
*/
|
||||
protected $vendorSpecificInfo = array();
|
||||
|
||||
/**
|
||||
* Database Connection.
|
||||
* @var Connection
|
||||
*/
|
||||
protected $conn;
|
||||
|
||||
/**
|
||||
* The parent DatabaseInfo object.
|
||||
* @var DatabaseInfo
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/** Shortcut to db resource link id (needed by drivers for queries). */
|
||||
protected $dblink;
|
||||
|
||||
/** Shortcut to db name (needed by many drivers for queries). */
|
||||
protected $dbname;
|
||||
|
||||
/**
|
||||
* @param string $table The table name.
|
||||
* @param string $database The database name.
|
||||
* @param resource $dblink The db connection resource.
|
||||
*/
|
||||
function __construct(DatabaseInfo $database, $name) {
|
||||
$this->database = $database;
|
||||
$this->name = $name;
|
||||
$this->conn = $database->getConnection(); // shortcut because all drivers need this for the queries
|
||||
$this->dblink = $this->conn->getResource();
|
||||
$this->dbname = $database->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* This "magic" method is invoked upon serialize().
|
||||
* Because the Info class hierarchy is recursive, we must handle
|
||||
* the serialization and unserialization of this object.
|
||||
* @return array The class variables that should be serialized (all must be public!).
|
||||
*/
|
||||
function __sleep()
|
||||
{
|
||||
return array('name', 'columns', 'foreignKeys', 'indexes', 'primaryKey');
|
||||
}
|
||||
|
||||
/**
|
||||
* This "magic" method is invoked upon unserialize().
|
||||
* This method re-hydrates the object and restores the recursive hierarchy.
|
||||
*/
|
||||
function __wakeup()
|
||||
{
|
||||
// restore chaining
|
||||
foreach($this->columns as $col) {
|
||||
$col->table = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the columns.
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function initColumns();
|
||||
|
||||
/**
|
||||
* Loads the primary key information for this table.
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function initPrimaryKey();
|
||||
|
||||
/**
|
||||
* Loads the foreign keys for this table.
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function initForeignKeys();
|
||||
|
||||
/**
|
||||
* Loads the indexes information for this table.
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function initIndexes();
|
||||
|
||||
/**
|
||||
* Loads the vendor specific information for this table.
|
||||
* @return void
|
||||
*/
|
||||
//it must be asbtract and be implemented in every vendor specific driver,
|
||||
//however since it's an experimental stuff it has an empty body in order
|
||||
//not to break BC
|
||||
/*abstract*/ protected function initVendorSpecificInfo(){}
|
||||
|
||||
/**
|
||||
* Get parimary key in this table.
|
||||
* @throws Exception - if foreign keys are unsupported by DB.
|
||||
* @return array ForeignKeyInfo[]
|
||||
*/
|
||||
public function getPrimaryKey()
|
||||
{
|
||||
if(!$this->pkLoaded) $this->initPrimaryKey();
|
||||
return $this->primaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ColumnInfo object for specified column.
|
||||
* @param string $name The column name.
|
||||
* @return ColumnInfo
|
||||
* @throws SQLException - if column does not exist for this table.
|
||||
*/
|
||||
public function getColumn($name)
|
||||
{
|
||||
if(!$this->colsLoaded) $this->initColumns();
|
||||
if (!isset($this->columns[$name])) {
|
||||
throw new SQLException("Table `".$this->name."` has no column `".$name."`");
|
||||
}
|
||||
return $this->columns[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether table contains specified column.
|
||||
* @param string $name The column name.
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasColumn($name)
|
||||
{
|
||||
if(!$this->colsLoaded) $this->initColumns();
|
||||
return isset($this->columns[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of columns for this table.
|
||||
* @return array ColumnInfo[]
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
if(!$this->colsLoaded) $this->initColumns();
|
||||
return array_values($this->columns); // re-key numerically
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specified fk for this table.
|
||||
* @param string $name The foreign key name to retrieve.
|
||||
* @return ForeignKeyInfo
|
||||
* @throws SQLException - if fkey does not exist for this table.
|
||||
*/
|
||||
public function getForeignKey($name)
|
||||
{
|
||||
if(!$this->fksLoaded) $this->initForeignKeys();
|
||||
if (!isset($this->foreignKeys[$name])) {
|
||||
throw new SQLException("Table `".$this->name."` has no foreign key `".$name."`");
|
||||
}
|
||||
return $this->foreignKeys[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all foreign keys.
|
||||
* @return array ForeignKeyInfo[]
|
||||
*/
|
||||
public function getForeignKeys()
|
||||
{
|
||||
if(!$this->fksLoaded) $this->initForeignKeys();
|
||||
return array_values($this->foreignKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IndexInfo object for a specified index.
|
||||
* @param string $name The index name to retrieve.
|
||||
* @return IndexInfo
|
||||
* @throws SQLException - if index does not exist for this table.
|
||||
*/
|
||||
public function getIndex($name)
|
||||
{
|
||||
if(!$this->indexesLoaded) $this->initIndexes();
|
||||
if (!isset($this->indexes[$name])) {
|
||||
throw new SQLException("Table `".$this->name."` has no index `".$name."`");
|
||||
}
|
||||
return $this->indexes[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of IndexInfo objects for this table.
|
||||
* @return array IndexInfo[]
|
||||
*/
|
||||
public function getIndexes()
|
||||
{
|
||||
if(!$this->indexesLoaded) $this->initIndexes();
|
||||
return array_values($this->indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for getIndexes() method.
|
||||
* @return array
|
||||
*/
|
||||
public function getIndices()
|
||||
{
|
||||
return $this->getIndexes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get table name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/** Have foreign keys been loaded? */
|
||||
public function foreignKeysLoaded()
|
||||
{
|
||||
return $this->fksLoaded;
|
||||
}
|
||||
|
||||
/** Has primary key info been loaded? */
|
||||
public function primaryKeyLoaded()
|
||||
{
|
||||
return $this->pkLoaded;
|
||||
}
|
||||
|
||||
/** Have columns been loaded? */
|
||||
public function columnsLoaded()
|
||||
{
|
||||
return $this->colsLoaded;
|
||||
}
|
||||
|
||||
/** Has index information been loaded? */
|
||||
public function indexesLoaded()
|
||||
{
|
||||
return $this->indexesLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vendor specific optional information for this table.
|
||||
* @return array vendorSpecificInfo[]
|
||||
*/
|
||||
public function getVendorSpecificInfo()
|
||||
{
|
||||
if(!$this->vendorLoaded) $this->initVendorSpecificInfo();
|
||||
return $this->vendorSpecificInfo;
|
||||
}
|
||||
|
||||
/** Adds a column to this table. */
|
||||
public function addColumn(ColumnInfo $column)
|
||||
{
|
||||
$this->columns[$column->getName()] = $column;
|
||||
}
|
||||
|
||||
/** Get the parent DatabaseInfo object. */
|
||||
public function getDatabase()
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: Blob.php,v 1.5 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/util/Lob.php';
|
||||
|
||||
/**
|
||||
* A class for handling binary LOBs.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.5 $
|
||||
* @package creole.util
|
||||
*/
|
||||
class Blob extends Lob {
|
||||
|
||||
/**
|
||||
* Dump the contents of the file using fpassthru().
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception if no file or contents.
|
||||
*/
|
||||
function dump()
|
||||
{
|
||||
if (!$this->data) {
|
||||
// hmmm .. must be a file that needs to read in
|
||||
if ($this->inFile) {
|
||||
$fp = @fopen($this->inFile, "rb");
|
||||
if (!$fp) {
|
||||
throw new Exception('Unable to open file: '.$this->inFile);
|
||||
}
|
||||
fpassthru($fp);
|
||||
@fclose($fp);
|
||||
} else {
|
||||
throw new Exception('No data to dump');
|
||||
}
|
||||
|
||||
} else {
|
||||
echo $this->data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: Clob.php,v 1.6 2004/07/27 23:15:13 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/util/Lob.php';
|
||||
|
||||
/**
|
||||
* A class for handling character (ASCII) LOBs.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.6 $
|
||||
* @package creole.util
|
||||
*/
|
||||
class Clob extends Lob {
|
||||
|
||||
/**
|
||||
* Read LOB data from file.
|
||||
* @param string $file Filename may also be specified here (if not specified using setInputFile()).
|
||||
* @return void
|
||||
* @throws Exception - if no file specified or error on read.
|
||||
* @see setInputFile()
|
||||
*/
|
||||
public function readFromFile($file = null)
|
||||
{
|
||||
if ($file !== null) {
|
||||
$this->setInputFile($file);
|
||||
}
|
||||
if (!$this->inFile) {
|
||||
throw Exception('No file specified for read.');
|
||||
}
|
||||
$data = null;
|
||||
$file = fopen($this->inFile, "rt");
|
||||
while (!feof($file)) $data .= fgets($file, 4096);
|
||||
fclose($file);
|
||||
if ($data === false) {
|
||||
throw new Exception('Unable to read from file: '.$this->inFile);
|
||||
}
|
||||
$this->setContents($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write LOB data to file.
|
||||
* @param string $file Filename may also be specified here (if not set using setOutputFile()).
|
||||
* @throws Exception - if no file specified, no contents to write, or error on write.
|
||||
* @see setOutputFile()
|
||||
*/
|
||||
public function writeToFile($file = null)
|
||||
{
|
||||
if ($file !== null) {
|
||||
$this->setOutputFile($file);
|
||||
}
|
||||
if (!$this->outFile) {
|
||||
throw new Exception('No file specified for write');
|
||||
}
|
||||
if ($this->data === null) {
|
||||
throw new Exception('No data to write to file');
|
||||
}
|
||||
$file = fopen($this->inFile, "wt");
|
||||
if (fputs($file, $this->data) === false)
|
||||
throw new Exception('Unable to write to file: '.$this->outFile);
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the contents of the file using fpassthru().
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception if no file or contents.
|
||||
*/
|
||||
function dump()
|
||||
{
|
||||
if (!$this->data) {
|
||||
|
||||
// is there a file name set?
|
||||
if ($this->inFile) {
|
||||
$fp = @fopen($this->inFile, "r");
|
||||
if (!$fp) {
|
||||
throw new Exception('Unable to open file: '.$this->inFile);
|
||||
}
|
||||
fpassthru($fp);
|
||||
@fclose($fp);
|
||||
} else {
|
||||
throw new Exception('No data to dump');
|
||||
}
|
||||
|
||||
} else {
|
||||
echo $this->data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: Lob.php,v 1.10 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An abstract class for handling LOB (Locator Object) columns.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.10 $
|
||||
* @package creole.util
|
||||
*/
|
||||
abstract class Lob {
|
||||
|
||||
/**
|
||||
* The contents of the Lob.
|
||||
* DO NOT SET DIRECTLY (or you will disrupt the
|
||||
* ability of isModified() to give accurate results).
|
||||
* @var string
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* File that blob should be written out to.
|
||||
* @var string
|
||||
*/
|
||||
protected $outFile;
|
||||
|
||||
/**
|
||||
* File that blob should be read in from
|
||||
* @var string
|
||||
*/
|
||||
protected $inFile;
|
||||
|
||||
/**
|
||||
* This is a 3-state value indicating whether column has been
|
||||
* modified.
|
||||
* Initially it is NULL. Once first call to setContents() is made
|
||||
* it is FALSE, because this will be initial state of Lob. Once
|
||||
* a subsequent call to setContents() is made it is TRUE.
|
||||
* @var boolean
|
||||
*/
|
||||
private $modified = null;
|
||||
|
||||
/**
|
||||
* Construct a new Lob.
|
||||
* @param sttring $data The data contents of the Lob.
|
||||
* @see setContents()
|
||||
*/
|
||||
public function __construct($data = null)
|
||||
{
|
||||
if ($data !== null) {
|
||||
$this->setContents($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of the LOB.
|
||||
* @return string The characters in this LOB.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getContents()
|
||||
{
|
||||
if ($this->data === null && $this->isFromFile()) {
|
||||
$this->readFromFile();
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contents of this LOB.
|
||||
* Sets the modified flag to FALSE if this is the first call
|
||||
* to setContents() for this object. Sets the bit to TRUE if
|
||||
* this any subsequent call to setContents().
|
||||
* @param string $bytes
|
||||
*/
|
||||
public function setContents($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
if ($this->modified === null) {
|
||||
// if modified bit hasn't been set yet,
|
||||
// then it should now be set to FALSE, since
|
||||
// we just did inital population
|
||||
$this->modified = false;
|
||||
} elseif ($this->modified === false) {
|
||||
// if it was already FALSE, then it should
|
||||
// now be set to TRUE, since this is a subsequent
|
||||
// modfiication.
|
||||
$this->modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the contents of the file to stdout.
|
||||
* Must be implemented by subclasses so that binary status is handled
|
||||
* correctly. (i.e. ignored for Clob, handled for Blob)
|
||||
* @return void
|
||||
* @throws Exception if no file or contents.
|
||||
*/
|
||||
abstract public function dump();
|
||||
|
||||
/**
|
||||
* Specify the file that we want this LOB read from.
|
||||
* @param string $filePath The location of the file.
|
||||
* @return void
|
||||
*/
|
||||
public function setInputFile($filePath)
|
||||
{
|
||||
$this->inFile = $filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file that we want this LOB read from.
|
||||
* @return string The location of the file.
|
||||
*/
|
||||
public function getInputFile()
|
||||
{
|
||||
return $this->inFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the file that we want this LOB saved to.
|
||||
* @param string $filePath The location of the file.
|
||||
* @return void
|
||||
*/
|
||||
public function setOutputFile($filePath)
|
||||
{
|
||||
$this->outFile = $filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file that we want this LOB saved to.
|
||||
* @return string $filePath The location of the file.
|
||||
*/
|
||||
public function getOutputFile()
|
||||
{
|
||||
return $this->outFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this Lob is loaded from file.
|
||||
* This is useful for bypassing need to read in the contents of the Lob.
|
||||
* @return boolean Whether this LOB is to be read from a file.
|
||||
*/
|
||||
public function isFromFile()
|
||||
{
|
||||
return ($this->inFile !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read LOB data from file (binary safe).
|
||||
* (Implementation may need to be moved into Clob / Blob subclasses, but
|
||||
* since file_get_contents() is binary-safe, it hasn't been necessary so far.)
|
||||
* @param string $file Filename may also be specified here (if not specified using setInputFile()).
|
||||
* @return void
|
||||
* @throws Exception - if no file specified or error on read.
|
||||
* @see setInputFile()
|
||||
*/
|
||||
public function readFromFile($file = null)
|
||||
{
|
||||
if ($file !== null) {
|
||||
$this->setInputFile($file);
|
||||
}
|
||||
if (!$this->inFile) {
|
||||
throw Exception('No file specified for read.');
|
||||
}
|
||||
$data = @file_get_contents($this->inFile);
|
||||
if ($data === false) {
|
||||
throw new Exception('Unable to read from file: '.$this->inFile);
|
||||
}
|
||||
$this->setContents($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write LOB data to file (binary safe).
|
||||
* (Impl may need to move into subclasses, but so far not necessary.)
|
||||
* @param string $file Filename may also be specified here (if not set using setOutputFile()).
|
||||
* @throws Exception - if no file specified, no contents to write, or error on write.
|
||||
* @see setOutputFile()
|
||||
*/
|
||||
public function writeToFile($file = null)
|
||||
{
|
||||
if ($file !== null) {
|
||||
$this->setOutputFile($file);
|
||||
}
|
||||
if (!$this->outFile) {
|
||||
throw new Exception('No file specified for write');
|
||||
}
|
||||
if ($this->data === null) {
|
||||
throw new Exception('No data to write to file');
|
||||
}
|
||||
if (false === @file_put_contents($this->outFile, $this->data)) {
|
||||
throw new Exception('Unable to write to file: '.$this->outFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get contents of LOB as string.
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether LOB contents have been modified after initial setting.
|
||||
* @param boolean $b
|
||||
*/
|
||||
public function setModified($b)
|
||||
{
|
||||
$this->modified = $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether LOB contents have been modified after initial setting.
|
||||
* @return boolean TRUE if the contents have been modified after initial setting.
|
||||
* FALSE if contents have not been modified or if no contents have bene set.
|
||||
*/
|
||||
public function isModified()
|
||||
{
|
||||
// cast it so that NULL will also eval to false
|
||||
return (boolean) $this->modified;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id: SQLStatementExtractor.php,v 1.5 2004/07/27 23:13:46 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Static class for extracting SQL statements from a string or file.
|
||||
*
|
||||
* @author Hans Lellelid <hans@xmpl.org>
|
||||
* @version $Revision: 1.5 $
|
||||
* @package creole.util.sql
|
||||
*/
|
||||
class SQLStatementExtractor {
|
||||
|
||||
protected static $delimiter = ';';
|
||||
|
||||
/**
|
||||
* Get SQL statements from file.
|
||||
*
|
||||
* @param string $filename Path to file to read.
|
||||
* @return array SQL statements
|
||||
*/
|
||||
public static function extractFile($filename) {
|
||||
$buffer = file_get_contents($filename);
|
||||
if ($buffer === false) {
|
||||
throw new Exception("Unable to read file: " . $filename);
|
||||
}
|
||||
return self::extractStatements(self::getLines($buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract statements from string.
|
||||
*
|
||||
* @param string $txt
|
||||
* @return array
|
||||
*/
|
||||
public static function extract($buffer) {
|
||||
return self::extractStatements(self::getLines($buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract SQL statements from array of lines.
|
||||
*
|
||||
* @param array $lines Lines of the read-in file.
|
||||
* @return string
|
||||
*/
|
||||
protected static function extractStatements($lines) {
|
||||
|
||||
$statements = array();
|
||||
$sql = "";
|
||||
|
||||
foreach($lines as $line) {
|
||||
|
||||
$line = trim($line);
|
||||
|
||||
if (self::startsWith("//", $line) ||
|
||||
self::startsWith("--", $line) ||
|
||||
self::startsWith("#", $line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen($line) > 4 && strtoupper(substr($line,0, 4)) == "REM ") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql .= " " . $line;
|
||||
$sql = trim($sql);
|
||||
|
||||
// SQL defines "--" as a comment to EOL
|
||||
// and in Oracle it may contain a hint
|
||||
// so we cannot just remove it, instead we must end it
|
||||
if (strpos($line, "--") !== false) {
|
||||
$sql .= "\n";
|
||||
}
|
||||
|
||||
if (self::endsWith(self::$delimiter, $sql)) {
|
||||
$statements[] = self::substring($sql, 0, strlen($sql)-1 - strlen(self::$delimiter));
|
||||
$sql = "";
|
||||
}
|
||||
}
|
||||
return $statements;
|
||||
}
|
||||
|
||||
//
|
||||
// Some string helper methods
|
||||
//
|
||||
|
||||
/**
|
||||
* Tests if a string starts with a given string.
|
||||
* @param string $check The substring to check.
|
||||
* @param string $string The string to check in (haystack).
|
||||
* @return boolean True if $string starts with $check, or they are equal, or $check is empty.
|
||||
*/
|
||||
protected static function startsWith($check, $string) {
|
||||
if ($check === "" || $check === $string) {
|
||||
return true;
|
||||
} else {
|
||||
return (strpos($string, $check) === 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a string ends with a given string.
|
||||
* @param string $check The substring to check.
|
||||
* @param string $string The string to check in (haystack).
|
||||
* @return boolean True if $string ends with $check, or they are equal, or $check is empty.
|
||||
*/
|
||||
protected static function endsWith($check, $string) {
|
||||
if ($check === "" || $check === $string) {
|
||||
return true;
|
||||
} else {
|
||||
return (strpos(strrev($string), strrev($check)) === 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a natural way of getting a subtring, php's circular string buffer and strange
|
||||
* return values suck if you want to program strict as of C or friends
|
||||
*/
|
||||
protected static function substring($string, $startpos, $endpos = -1) {
|
||||
$len = strlen($string);
|
||||
$endpos = (int) (($endpos === -1) ? $len-1 : $endpos);
|
||||
if ($startpos > $len-1 || $startpos < 0) {
|
||||
trigger_error("substring(), Startindex out of bounds must be 0<n<$len", E_USER_ERROR);
|
||||
}
|
||||
if ($endpos > $len-1 || $endpos < $startpos) {
|
||||
trigger_error("substring(), Endindex out of bounds must be $startpos<n<".($len-1), E_USER_ERROR);
|
||||
}
|
||||
if ($startpos === $endpos) {
|
||||
return (string) $string{$startpos};
|
||||
} else {
|
||||
$len = $endpos-$startpos;
|
||||
}
|
||||
return substr($string, $startpos, $len+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string buffer into array of lines.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array string[] lines of file.
|
||||
*/
|
||||
protected static function getLines($buffer) {
|
||||
$lines = preg_split("/\r?\n|\r/", $buffer);
|
||||
return $lines;
|
||||
}
|
||||
|
||||
}
|
||||
267
h2o.php
267
h2o.php
|
|
@ -1,267 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @package h2o
|
||||
*/
|
||||
define('H2O_VERSION', '0.3');
|
||||
defined('DS') or define('DS', DIRECTORY_SEPARATOR);
|
||||
defined('H2O_ROOT') or define('H2O_ROOT', dirname(__FILE__) . DS);
|
||||
|
||||
require H2O_ROOT.'h2o/datatype.php';
|
||||
require H2O_ROOT.'h2o/loaders.php';
|
||||
require H2O_ROOT.'h2o/nodes.php';
|
||||
require H2O_ROOT.'h2o/tags.php';
|
||||
require H2O_ROOT.'h2o/errors.php';
|
||||
require H2O_ROOT.'h2o/filters.php';
|
||||
require H2O_ROOT.'h2o/context.php';
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* $h2o = new H2O('./template.html', array("loader"=>'file'));
|
||||
*
|
||||
*
|
||||
* $h2o = new H2O('template.html', array("loader"=>'hash'));
|
||||
*/
|
||||
class H2o {
|
||||
var $searchpath;
|
||||
var $context;
|
||||
var $loader = false;
|
||||
|
||||
static $tags = array();
|
||||
static $filters = array();
|
||||
static $extensions = array();
|
||||
|
||||
function getOptions($options = array()) {
|
||||
return array_merge(array(
|
||||
'loader' => 'file',
|
||||
'cache' => 'file', // file | apc | memcache
|
||||
'cache_prefix' => 'h2o_',
|
||||
'cache_ttl' => 3600, // file | apc | memcache
|
||||
'searchpath' => false,
|
||||
'autoescape' => true,
|
||||
|
||||
// Enviroment setting
|
||||
'BLOCK_START' => '{%',
|
||||
'BLOCK_END' => '%}',
|
||||
'VARIABLE_START' => '{{',
|
||||
'VARIABLE_END' => '}}',
|
||||
'COMMENT_START' => '{*',
|
||||
'COMMENT_END' => '*}',
|
||||
'TRIM_TAGS' => true
|
||||
), $options);
|
||||
}
|
||||
|
||||
function __construct($file = null, $options = array()) {
|
||||
# Init a environment
|
||||
$this->options = $this->getOptions($options);
|
||||
$loader = $this->options['loader'];
|
||||
|
||||
if (!$loader)
|
||||
return true;
|
||||
|
||||
if (is_object($loader)) {
|
||||
$this->loader = $loader;
|
||||
$this->loader->setOptions($this->options);
|
||||
} else {
|
||||
$loader = "H2o_{$loader}_Loader";
|
||||
if (!class_exists($loader, false))
|
||||
throw new Exception('Invalid template loader');
|
||||
|
||||
if (isset($options['searchpath']))
|
||||
$this->searchpath = realpath($options['searchpath']).DS;
|
||||
elseif ($file)
|
||||
$this->searchpath = dirname(realpath($file)).DS;
|
||||
else
|
||||
$this->searchpath = getcwd().DS;
|
||||
|
||||
$this->loader = new $loader($this->searchpath, $this->options);
|
||||
}
|
||||
$this->loader->runtime = $this;
|
||||
|
||||
if (isset($options['i18n'])) {
|
||||
h2o::load('i18n');
|
||||
$this->i18n = new H2o_I18n($this->searchpath, $options['i18n']);
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
$this->nodelist = $this->loadTemplate($file);
|
||||
}
|
||||
}
|
||||
|
||||
function loadTemplate($file) {
|
||||
return $this->nodelist = $this->loader->read_cache($file);
|
||||
}
|
||||
|
||||
function loadSubTemplate($file) {
|
||||
return $this->loader->read($file);
|
||||
}
|
||||
|
||||
# Build a finalized nodelist from template ready to be cached
|
||||
function parse($source, $filename = '', $env = null) {
|
||||
if (!$env)
|
||||
$env = $this->options;
|
||||
|
||||
if (!class_exists('H2o_Parser', false))
|
||||
require H2O_ROOT.'h2o/parser.php';
|
||||
|
||||
$parser = new H2o_Parser($source, $filename, $this, $env);
|
||||
$nodelist = $parser->parse();
|
||||
return $nodelist;
|
||||
}
|
||||
|
||||
function set($context, $value = null) {
|
||||
# replace with new context object
|
||||
if (is_object($context) && $context instanceof H2o_Context) {
|
||||
return $this->context = $context;
|
||||
}
|
||||
|
||||
# Init context
|
||||
if (!$this->context) {
|
||||
$this->context = new H2o_Context($this->defaultContext(), $this->options);
|
||||
}
|
||||
|
||||
# Extend or set value
|
||||
if (is_array($context)) {
|
||||
return $this->context->extend($context);
|
||||
}
|
||||
elseif (is_string($context)) {
|
||||
return $this->context[$context] = $value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# Render the nodelist
|
||||
function render($context = array()) {
|
||||
$this->set($context);
|
||||
|
||||
$this->stream = new StreamWriter;
|
||||
$this->nodelist->render($this->context, $this->stream);
|
||||
return $this->stream->close();
|
||||
}
|
||||
|
||||
static function parseString($source, $options = array()) {
|
||||
$instance = new H2o(null, array_merge($options, array('loader' => false)));
|
||||
$instance->nodelist = $instance->parse($source);
|
||||
return $instance;
|
||||
}
|
||||
|
||||
static function &createTag($tag, $args = null, $parser, $position = 0) {
|
||||
if (!isset(self::$tags[$tag])) {
|
||||
throw new H2o_Error($tag . " tag doesn't exist");
|
||||
}
|
||||
$tagClass = self::$tags[$tag];
|
||||
$tag = new $tagClass($args, $parser, $position);
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new tag
|
||||
*
|
||||
*
|
||||
* h2o::addTag('tag_name', 'ClassName');
|
||||
*
|
||||
* h2o::addTag(array(
|
||||
* 'tag_name' => 'MagClass',
|
||||
* 'tag_name2' => 'TagClass2'
|
||||
* ));
|
||||
*
|
||||
* h2o::addTag('tag_name'); // Tag_name_Tag
|
||||
*
|
||||
* h2o::addTag(array('tag_name',
|
||||
* @param unknown_type $tag
|
||||
* @param unknown_type $class
|
||||
*/
|
||||
static function addTag($tag, $class = null) {
|
||||
$tags = array();
|
||||
if (is_string($tag)) {
|
||||
if (is_null($class))
|
||||
$class = ucwords("{$tag}_Tag");
|
||||
$tags[$tag] = $class;
|
||||
} elseif (is_array($tag)) {
|
||||
$tags = $tag;
|
||||
}
|
||||
|
||||
foreach ($tags as $tag => $tagClass) {
|
||||
if (is_integer($tag)) {
|
||||
unset($tags[$tag]);
|
||||
$tag = $tagClass;
|
||||
$tagClass = ucwords("{$tagClass}_Tag");
|
||||
}
|
||||
if (!class_exists($tagClass, false)) {
|
||||
throw new H2o_Error("{$tagClass} tag is not found");
|
||||
}
|
||||
$tags[$tag] = $tagClass;
|
||||
}
|
||||
self::$tags = array_merge(self::$tags, $tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new filter to h2o runtime
|
||||
*
|
||||
* @param unknown_type $filter
|
||||
* @param unknown_type $callback
|
||||
* @return unknown
|
||||
*/
|
||||
static function addFilter($filter, $callback = null) {
|
||||
if (is_array($filter)) {
|
||||
$filters = $filter;
|
||||
foreach($filters as $key => $filter) {
|
||||
if (is_numeric($key))
|
||||
$key = $filter;
|
||||
self::addFilter($key, $filter);
|
||||
}
|
||||
return true;
|
||||
} elseif (is_string($filter) && class_exists($filter, false) && is_subclass_of($filter, 'FilterCollection')) {
|
||||
foreach (get_class_methods($filter) as $f) {
|
||||
if (is_callable(array($filter, $f)))
|
||||
self::$filters[$f] = array($filter, $f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (is_null($callback))
|
||||
$callback = $filter;
|
||||
|
||||
if (!is_callable($callback)) {
|
||||
return false;
|
||||
}
|
||||
self::$filters[$filter] = $callback;
|
||||
}
|
||||
|
||||
static function addLookup($callback) {
|
||||
if (is_callable($callback)) {
|
||||
H2o_Context::$lookupTable[] = $callback;
|
||||
} else die('damm it');
|
||||
}
|
||||
|
||||
static function load($extension, $file = null) {
|
||||
if (!$file) {
|
||||
$file = H2O_ROOT.'ext'.DS.$extension.'.php';
|
||||
}
|
||||
if (is_file($file)) {
|
||||
include_once ($file);
|
||||
self::$extensions[$extension] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
function defaultContext() {
|
||||
return array('h2o' => new H2o_Info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient wrapper for loading template file or string
|
||||
* @param $name
|
||||
* @param $options - H2o options
|
||||
* @return Instance of H2o Template
|
||||
*/
|
||||
function h2o($name, $options = array()) {
|
||||
$is_file = '/([^\s]*?)(\.[^.\s]*$)/';
|
||||
|
||||
if (!preg_match($is_file, $name)) {
|
||||
return H2o::parseString($name, $options);
|
||||
}
|
||||
|
||||
$instance = new H2o($name, $options);
|
||||
return $instance;
|
||||
}
|
||||
|
||||
?>
|
||||
264
h2o/context.php
264
h2o/context.php
|
|
@ -1,264 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Context object
|
||||
* encapsulate context, resolve name
|
||||
* @package h2o.context
|
||||
*/
|
||||
class H2o_Context implements ArrayAccess {
|
||||
public $safeClass = array('stdClass', 'BlockContext');
|
||||
public $scopes;
|
||||
public $options;
|
||||
public $autoescape = true;
|
||||
|
||||
private $arrayMethods = array('first'=> 0, 'last'=> 1, 'length'=> 2, 'size'=> 3);
|
||||
static $lookupTable = array();
|
||||
|
||||
function __construct($context = array(), $options = array()){
|
||||
if (is_object($context))
|
||||
$context = get_object_vars($context);
|
||||
$this->scopes = array($context);
|
||||
|
||||
if (isset($options['safeClass']))
|
||||
$this->safeClass = array_merge($this->safeClass, $options['safeClass']);
|
||||
|
||||
if (isset($options['autoescape']))
|
||||
$this->autoescape = $options['autoescape'];
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
function push($layer = array()){
|
||||
return array_unshift($this->scopes, $layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* pop the most recent layer
|
||||
*/
|
||||
function pop() {
|
||||
if (!isset($this->scopes[1]))
|
||||
throw new Exception('cannnot pop from empty stack');
|
||||
return array_shift($this->scopes);
|
||||
}
|
||||
|
||||
function offsetExists($offset) {
|
||||
foreach ($this->scopes as $layer) {
|
||||
if (isset($layer[$offset])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function offsetGet($key) {
|
||||
foreach ($this->scopes as $layer) {
|
||||
if (isset($layer[$key]))
|
||||
return $layer[$key];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
function offsetSet($key, $value) {
|
||||
if (strpos($key, '.') > -1)
|
||||
throw new Exception('cannot set non local variable');
|
||||
return $this->scopes[0][$key] = $value;
|
||||
}
|
||||
|
||||
function offsetUnset($key) {
|
||||
foreach ($this->scopes as $layer) {
|
||||
if (isset($layer[$key])) unset($layer[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
function extend($context) {
|
||||
$this->scopes[0] = array_merge($this->scopes[0], $context);
|
||||
}
|
||||
|
||||
function set($key, $value) {
|
||||
return $this->offsetSet($key, $value);
|
||||
}
|
||||
|
||||
function get($key) {
|
||||
return $this->offsetGet($key);
|
||||
}
|
||||
|
||||
function isDefined($key) {
|
||||
return $this->offsetExists($key);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
* Variable name
|
||||
*
|
||||
* @param $var variable name or array(0 => variable name, 'filters' => filters array)
|
||||
* @return unknown_type
|
||||
*/
|
||||
function resolve($var) {
|
||||
|
||||
# if $var is array - it contains filters to apply
|
||||
$filters = array();
|
||||
if ( is_array($var) ) {
|
||||
|
||||
$name = array_shift($var);
|
||||
$filters = isset($var['filters'])? $var['filters'] : array();
|
||||
|
||||
}
|
||||
else $name = $var;
|
||||
|
||||
$result = null;
|
||||
|
||||
# Lookup basic types, null, boolean, numeric and string
|
||||
# Variable starts with : (:users.name) to short-circuit lookup
|
||||
if ($name[0] === ':') {
|
||||
$object = $this->getVariable(substr($name, 1));
|
||||
if (!is_null($object)) $result = $object;
|
||||
} else {
|
||||
if ($name === 'true') {
|
||||
$result = true;
|
||||
}
|
||||
elseif ($name === 'false') {
|
||||
$result = false;
|
||||
}
|
||||
elseif (preg_match('/^-?\d+(\.\d+)?$/', $name, $matches)) {
|
||||
$result = isset($matches[1])? floatval($name) : intval($name);
|
||||
}
|
||||
elseif (preg_match('/^"([^"\\\\]*(?:\\.[^"\\\\]*)*)"|' .
|
||||
'\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'$/', $name)) {
|
||||
$result = stripcslashes(substr($name, 1, -1));
|
||||
}
|
||||
}
|
||||
if (!empty(self::$lookupTable)) {
|
||||
$result = $this->externalLookup($name);
|
||||
}
|
||||
$result = $this->applyFilters($result,$filters);
|
||||
return $result;
|
||||
}
|
||||
|
||||
function getVariable($name) {
|
||||
# Local variables. this gives as a bit of performance improvement
|
||||
if (!strpos($name, '.'))
|
||||
return $this[$name];
|
||||
|
||||
# Prepare for Big lookup
|
||||
$parts = explode('.', $name);
|
||||
$object = $this[array_shift($parts)];
|
||||
|
||||
# Lookup context
|
||||
foreach ($parts as $part) {
|
||||
if (is_array($object) or $object instanceof ArrayAccess) {
|
||||
if (isset($object[$part]))
|
||||
$object = $object[$part];
|
||||
elseif ($part === 'first')
|
||||
$object = $object[0];
|
||||
elseif ($part === 'last')
|
||||
$object = $object[count($object) -1];
|
||||
elseif ($part === 'size' or $part === 'length')
|
||||
return count($object);
|
||||
else return null;
|
||||
}
|
||||
elseif (is_object($object)) {
|
||||
if (isset($object->$part))
|
||||
$object = $object->$part;
|
||||
elseif (is_callable(array($object, $part))) {
|
||||
$methodAllowed = in_array(get_class($object), $this->safeClass) ||
|
||||
(isset($object->h2o_safe) && (
|
||||
$object->h2o_safe === true || in_array($part, $object->h2o_safe)
|
||||
)
|
||||
);
|
||||
$object = $methodAllowed ? $object->$part() : null;
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
function applyFilters($object, $filters) {
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
$name = substr(array_shift($filter), 1);
|
||||
$args = $filter;
|
||||
|
||||
if (isset(h2o::$filters[$name])) {
|
||||
foreach ($args as $i => $argument) {
|
||||
# name args
|
||||
if (is_array($argument)) {
|
||||
foreach ($argument as $n => $arg) {
|
||||
$args[$i][$n] = $this->resolve($arg);
|
||||
}
|
||||
} else {
|
||||
# resolve argument values
|
||||
$args[$i] = $this->resolve($argument);
|
||||
}
|
||||
}
|
||||
array_unshift($args, $object);
|
||||
$object = call_user_func_array(h2o::$filters[$name], $args);
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
function escape($value, $var) {
|
||||
|
||||
$safe = false;
|
||||
$filters = (is_array($var) && isset($var['filters']))? $var['filters'] : array();
|
||||
|
||||
foreach ( $filters as $filter ) {
|
||||
|
||||
$name = substr(array_shift($filter), 1);
|
||||
$safe = !$safe && ($name === 'safe');
|
||||
|
||||
$escaped = $name === 'escape';
|
||||
}
|
||||
|
||||
$should_escape = $this->autoescape || isset($escaped) && $escaped;
|
||||
|
||||
if ( ($should_escape && !$safe)) {
|
||||
$value = htmlspecialchars($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
function externalLookup($name) {
|
||||
if (!empty(self::$lookupTable)) {
|
||||
foreach (self::$lookupTable as $lookup) {
|
||||
$tmp = call_user_func_array($lookup, array($name, $this));
|
||||
if ($tmp !== null)
|
||||
return $tmp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class BlockContext {
|
||||
var $h2o_safe = array('name', 'depth', 'super');
|
||||
var $block, $index;
|
||||
private $context;
|
||||
|
||||
function __construct($block, $context, $index) {
|
||||
$this->block =& $block;
|
||||
$this->context = $context;
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
function name() {
|
||||
return $this->block->name;
|
||||
}
|
||||
|
||||
function depth() {
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
function super() {
|
||||
$stream = new StreamWriter;
|
||||
$this->block->parent->render($this->context, $stream, $this->index+1);
|
||||
return $stream->close();
|
||||
}
|
||||
|
||||
function __toString() {
|
||||
return "[BlockContext : {$this->block->name}, {$this->block->filename}]";
|
||||
}
|
||||
}
|
||||
?>
|
||||
176
h2o/datatype.php
176
h2o/datatype.php
|
|
@ -1,176 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @package h2o.datatype
|
||||
*/
|
||||
class StreamWriter {
|
||||
var $buffer = array();
|
||||
var $close;
|
||||
|
||||
function __construct() {
|
||||
$this->close = false;
|
||||
}
|
||||
|
||||
function write($data) {
|
||||
if ($this->close)
|
||||
new Exception('tried to write to closed stream');
|
||||
$this->buffer[] = $data;
|
||||
}
|
||||
|
||||
function close() {
|
||||
$this->close = true;
|
||||
return implode('', $this->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
class Evaluator {
|
||||
static function gt($l, $r) { return $l > $r; }
|
||||
static function ge($l, $r) { return $l >= $r; }
|
||||
|
||||
static function lt($l, $r) { return $l < $r; }
|
||||
static function le($l, $r) { return $l <= $r; }
|
||||
|
||||
static function eq($l, $r) { return $l == $r; }
|
||||
static function ne($l, $r) { return $l != $r; }
|
||||
|
||||
static function not_($bool) { return !$bool; }
|
||||
static function and_($l, $r) { return ($l && $r); }
|
||||
static function or_($l, $r) { return ($l && $r); }
|
||||
|
||||
# Currently only support single expression with no preceddence ,no boolean expression
|
||||
# [expression] = [optional binary] ? operant [ optional compare operant]
|
||||
# [operant] = variable|string|numeric|boolean
|
||||
# [compare] = > | < | == | >= | <=
|
||||
# [binary] = not | !
|
||||
static function exec($args, $context) {
|
||||
$argc = count($args);
|
||||
$first = array_shift($args);
|
||||
$first = $context->resolve($first);
|
||||
switch ($argc) {
|
||||
case 1 :
|
||||
return $first;
|
||||
case 2 :
|
||||
if (is_array($first) && isset($first['operator']) && $first['operator'] == 'not') {
|
||||
$operant = array_shift($args);
|
||||
$operant = $context->resolve($operant);
|
||||
return !($operant);
|
||||
}
|
||||
case 3 :
|
||||
list($op, $right) = $args;
|
||||
$right = $context->resolve($right);
|
||||
return call_user_func(array("Evaluator", $op['operator']), $first, $right);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* $type of token, Block | Variable
|
||||
*/
|
||||
class H2o_Token {
|
||||
function __construct ($type, $content, $position) {
|
||||
$this->type = $type;
|
||||
$this->content = $content;
|
||||
$this->result='';
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
function write($content){
|
||||
$this->result= $content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a token stream
|
||||
*/
|
||||
class TokenStream {
|
||||
var $pushed;
|
||||
var $stream;
|
||||
var $closed;
|
||||
var $c;
|
||||
|
||||
function __construct() {
|
||||
$this->pushed = array();
|
||||
$this->stream = array();
|
||||
$this->closed = false;
|
||||
}
|
||||
|
||||
function pop() {
|
||||
if (count($this->pushed))
|
||||
return array_pop($this->pushed);
|
||||
return array_pop($this->stream);
|
||||
}
|
||||
|
||||
function feed($type, $contents, $position) {
|
||||
if ($this->closed)
|
||||
throw new Exception('cannot feed closed stream');
|
||||
$this->stream[] = new H2o_Token($type, $contents, $position);
|
||||
}
|
||||
|
||||
function push($token) {
|
||||
if (is_null($token))
|
||||
throw new Exception('cannot push NULL');
|
||||
if ($this->closed)
|
||||
$this->pushed[] = $token;
|
||||
else
|
||||
$this->stream[] = $token;
|
||||
}
|
||||
|
||||
function close() {
|
||||
if ($this->closed)
|
||||
new Exception('cannot close already closed stream');
|
||||
$this->closed = true;
|
||||
$this->stream = array_reverse($this->stream);
|
||||
}
|
||||
|
||||
function isClosed() {
|
||||
return $this->closed;
|
||||
}
|
||||
|
||||
function current() {
|
||||
return $this->c ;
|
||||
}
|
||||
|
||||
function next() {
|
||||
return $this->c = $this->pop();
|
||||
}
|
||||
}
|
||||
|
||||
class H2o_Info {
|
||||
var $h2o_safe = array('filters', 'extensions', 'tags');
|
||||
var $name = 'H2o Template engine';
|
||||
var $description = "Django inspired template system";
|
||||
var $version = H2O_VERSION;
|
||||
|
||||
function filters() {
|
||||
return array_keys(h2o::$filters);
|
||||
}
|
||||
|
||||
function tags() {
|
||||
return array_keys(h2o::$tags);
|
||||
}
|
||||
|
||||
function extensions() {
|
||||
return array_keys(h2o::$extensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions
|
||||
*/
|
||||
function sym_to_str($string) {
|
||||
return substr($string, 1);
|
||||
}
|
||||
|
||||
function is_sym($string) {
|
||||
return isset($string[0]) && $string[0] === ':';
|
||||
}
|
||||
|
||||
function symbol($string) {
|
||||
return ':'.$string;
|
||||
}
|
||||
|
||||
function strip_regex($regex, $delimiter = '/') {
|
||||
return substr($regex, 1, strrpos($regex, $delimiter)-1);
|
||||
}
|
||||
?>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @package h2o.errors
|
||||
*/
|
||||
# Errors
|
||||
class H2o_Error extends Exception {}
|
||||
class ParseError extends H2o_Error {}
|
||||
class TemplateNotFound extends H2o_Error {}
|
||||
class TemplateSyntaxError extends H2o_Error {}
|
||||
|
||||
?>
|
||||
345
h2o/filters.php
345
h2o/filters.php
|
|
@ -1,345 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package h2o.filters
|
||||
*/
|
||||
class FilterCollection {};
|
||||
|
||||
|
||||
class CoreFilters extends FilterCollection {
|
||||
static function first($value) {
|
||||
return $value[0];
|
||||
}
|
||||
|
||||
static function last($value) {
|
||||
return $value[count($value) - 1];
|
||||
}
|
||||
|
||||
static function join($value, $delimiter = ', ') {
|
||||
return join($delimiter, $value);
|
||||
}
|
||||
|
||||
static function urlencode($data) {
|
||||
if (is_array($data)) {
|
||||
$result;
|
||||
foreach ($data as $name => $value) {
|
||||
$result .= $name.'='.urlencode($value).'&'.$querystring;
|
||||
}
|
||||
$querystring = substr($result, 0, strlen($result)-1);
|
||||
return htmlspecialchars($result);
|
||||
} else {
|
||||
return urlencode($data);
|
||||
}
|
||||
}
|
||||
|
||||
static function hyphenize ($string) {
|
||||
$rules = array('/[^\w\s-]+/'=>'','/\s+/'=>'-', '/-{2,}/'=>'-');
|
||||
$string = preg_replace(array_keys($rules), $rules, trim($string));
|
||||
return $string = trim(strtolower($string));
|
||||
}
|
||||
|
||||
static function urlize($url, $truncate = false) {
|
||||
if (preg_match('/^(http|https|ftp:\/\/([^\s"\']+))/i', $url, $match))
|
||||
$url = "<a href='{$url}'>". ($truncate ? truncate($url,$truncate): $url).'</a>';
|
||||
return $url;
|
||||
}
|
||||
|
||||
static function set_default($object, $default) {
|
||||
return !$object ? $default : $object;
|
||||
}
|
||||
}
|
||||
|
||||
class StringFilters extends FilterCollection {
|
||||
|
||||
static function humanize($string) {
|
||||
$string = preg_replace('/\s+/', ' ', trim(preg_replace('/[^A-Za-z0-9()!,?$]+/', ' ', $string)));
|
||||
return capfirst($string);
|
||||
}
|
||||
|
||||
static function capitalize($string) {
|
||||
return ucwords(strtolower($string)) ;
|
||||
}
|
||||
|
||||
static function titlize($string) {
|
||||
return self::capitalize($string);
|
||||
}
|
||||
|
||||
static function capfirst($string) {
|
||||
$string = strtolower($string);
|
||||
return strtoupper($string{0}). substr($string, 1, strlen($string));
|
||||
}
|
||||
|
||||
static function tighten_space($value) {
|
||||
return preg_replace("/\s{2,}/", ' ', $value);
|
||||
}
|
||||
|
||||
static function escape($value, $attribute = false) {
|
||||
return htmlspecialchars($value, $attribute ? ENT_QUOTES : ENT_NOQUOTES);
|
||||
}
|
||||
|
||||
static function force_escape($value, $attribute = false) {
|
||||
return self::escape($value, $attribute);
|
||||
}
|
||||
|
||||
static function e($value, $attribute = false) {
|
||||
return self::escape($value, $attribute);
|
||||
}
|
||||
|
||||
static function safe($value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
static function truncate ($string, $max = 50, $ends = '...') {
|
||||
return (strlen($string) > $max ? substr($string, 0, $max).$ends : $string);
|
||||
}
|
||||
|
||||
static function limitwords($text, $limit = 50, $ends = '...') {
|
||||
if (strlen($text) > $limit) {
|
||||
$words = str_word_count($text, 2);
|
||||
$pos = array_keys($words);
|
||||
|
||||
if (isset($pos[$limit])) {
|
||||
$text = substr($text, 0, $pos[$limit]) . $ends;
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
class NumberFilters extends FilterCollection {
|
||||
static function filesize ($bytes, $round = 1) {
|
||||
if ($bytes === 0)
|
||||
return '0 bytes';
|
||||
elseif ($bytes === 1)
|
||||
return '1 byte';
|
||||
|
||||
$units = array(
|
||||
'bytes' => pow(2, 0), 'kB' => pow(2, 10),
|
||||
'BM' => pow(2, 20), 'GB' => pow(2, 30),
|
||||
'TB' => pow(2, 40), 'PB' => pow(2, 50),
|
||||
'EB' => pow(2, 60), 'ZB' => pow(2, 70)
|
||||
);
|
||||
|
||||
$lastUnit = 'bytes';
|
||||
foreach ($units as $unitName => $unitFactor) {
|
||||
if ($bytes >= $unitFactor) {
|
||||
$lastUnit = $unitName;
|
||||
} else {
|
||||
$number = round( $bytes / $units[$lastUnit], $round );
|
||||
return number_format($number) . ' ' . $lastUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function currency($amount, $currency = 'USD', $precision = 2, $negateWithParentheses = false) {
|
||||
$definition = array(
|
||||
'EUR' => array('<27>','.',','), 'GBP' => '<27>', 'JPY' => '<27>',
|
||||
'USD'=>'$', 'AU' => '$', 'CAN' => '$'
|
||||
);
|
||||
$negative = false;
|
||||
$separator = ',';
|
||||
$decimals = '.';
|
||||
$currency = strtoupper($currency);
|
||||
|
||||
// Is negative
|
||||
if (strpos('-', $amount) !== false) {
|
||||
$negative = true;
|
||||
$amount = str_replace("-","",$amount);
|
||||
}
|
||||
$amount = (float) $amount;
|
||||
|
||||
if (!$negative) {
|
||||
$negative = $amount < 0;
|
||||
}
|
||||
if ($negateWithParentheses) {
|
||||
$amount = abs($amount);
|
||||
}
|
||||
|
||||
// Get rid of negative zero
|
||||
$zero = round(0, $precision);
|
||||
if (round($amount, $precision) === $zero) {
|
||||
$amount = $zero;
|
||||
}
|
||||
|
||||
if (isset($definition[$currency])) {
|
||||
$symbol = $definition[$currency];
|
||||
if (is_array($symbol))
|
||||
@list($symbol, $separator, $decimals) = $symbol;
|
||||
} else {
|
||||
$symbol = $currency;
|
||||
}
|
||||
$amount = number_format($amount, $precision, $decimals, $separator);
|
||||
|
||||
return $negateWithParentheses ? "({$symbol}{$amount})" : "{$symbol}{$amount}";
|
||||
}
|
||||
}
|
||||
|
||||
class HtmlFilters extends FilterCollection {
|
||||
static function base_url($url, $options = array()) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
static function asset_url($url, $options = array()) {
|
||||
return self::base_url($url, $options);
|
||||
}
|
||||
|
||||
static function image_tag($url, $options = array()) {
|
||||
$attr = self::htmlAttribute(array('alt','width','height','border'), $options);
|
||||
return sprintf('<img src="%s" %s/>', $url, $attr);
|
||||
}
|
||||
|
||||
static function css_tag($url, $options = array()) {
|
||||
$attr = self::htmlAttribute(array('media'), $options);
|
||||
return sprintf('<link rel="stylesheet" href="%s" type="text/css" %s />', $url, $attr);
|
||||
}
|
||||
|
||||
static function script_tag($url, $options = array()) {
|
||||
return sprintf('<script src="%s" type="text/javascript"></script>', $url);
|
||||
}
|
||||
|
||||
static function links_to($text, $url, $options = array()) {
|
||||
$attrs = self::htmlAttribute(array('ref'), $options);
|
||||
$url = self::base_url($url, $options);
|
||||
return sprintf('<a href="%s" %s>%s</a>', $url, $attrs, $text);
|
||||
}
|
||||
|
||||
static function links_with ($url, $text, $options = array()) {
|
||||
return self::links_to($text, $url, $options);
|
||||
}
|
||||
|
||||
static function strip_tags($text) {
|
||||
$text = preg_replace(array('/</', '/>/'), array(' <', '> '),$text);
|
||||
return strip_tags($text);
|
||||
}
|
||||
|
||||
static function linebreaks($value, $format = 'p') {
|
||||
if ($format === 'br')
|
||||
return HtmlFilters::nl2br($value);
|
||||
return HtmlFilters::nl2pbr($value);
|
||||
}
|
||||
|
||||
static function nl2br($value) {
|
||||
return str_replace("\n", "<br />\n", $value);
|
||||
}
|
||||
|
||||
static function nl2pbr($value) {
|
||||
$result = array();
|
||||
$parts = preg_split('/(\r?\n){2,}/m', $value);
|
||||
foreach ($parts as $part) {
|
||||
array_push($result, '<p>' . HtmlFilters::nl2br($part) . '</p>');
|
||||
}
|
||||
return implode("\n", $result);
|
||||
}
|
||||
|
||||
protected static function htmlAttribute($attrs = array(), $data = array()) {
|
||||
$attrs = self::extract(array_merge(array('id', 'class', 'title', "style"), $attrs), $data);
|
||||
|
||||
$result = array();
|
||||
foreach ($attrs as $name => $value) {
|
||||
$result[] = "{$name}=\"{$value}\"";
|
||||
}
|
||||
return join(' ', $result);
|
||||
}
|
||||
|
||||
protected static function extract($attrs = array(), $data=array()) {
|
||||
$result = array();
|
||||
if (empty($data)) return array();
|
||||
foreach($data as $k => $e) {
|
||||
if (in_array($k, $attrs)) $result[$k] = $e;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
class DatetimeFilters extends FilterCollection {
|
||||
static function date($time, $format = 'jS F Y H:i') {
|
||||
if ($time instanceof DateTime)
|
||||
$time = (int) $time->format('U');
|
||||
if (!is_numeric($time))
|
||||
$time = strtotime($time);
|
||||
|
||||
return date($format, $time);
|
||||
}
|
||||
|
||||
static function relative_time($timestamp, $format = 'g:iA') {
|
||||
if ($timestamp instanceof DateTime)
|
||||
$timestamp = (int) $timestamp->format('U');
|
||||
|
||||
$timestamp = is_numeric($timestamp) ? $timestamp: strtotime($timestamp);
|
||||
|
||||
$time = mktime(0, 0, 0);
|
||||
$delta = time() - $timestamp;
|
||||
$string = '';
|
||||
|
||||
if ($timestamp < $time - 86400) {
|
||||
return date("F j, Y, g:i a", $timestamp);
|
||||
}
|
||||
if ($delta > 86400 && $timestamp < $time) {
|
||||
return "Yesterday at " . date("g:i a", $timestamp);
|
||||
}
|
||||
|
||||
if ($delta > 7200)
|
||||
$string .= floor($delta / 3600) . " hours, ";
|
||||
else if ($delta > 3660)
|
||||
$string .= "1 hour, ";
|
||||
else if ($delta >= 3600)
|
||||
$string .= "1 hour ";
|
||||
$delta %= 3600;
|
||||
|
||||
if ($delta > 60)
|
||||
$string .= floor($delta / 60) . " minutes ";
|
||||
else
|
||||
$string .= $delta . " seconds ";
|
||||
return "$string ago";
|
||||
}
|
||||
|
||||
static function relative_date($time) {
|
||||
if ($time instanceof DateTime)
|
||||
$time = (int) $time->format('U');
|
||||
|
||||
$time = is_numeric($time) ? $time: strtotime($time);
|
||||
$today = strtotime(date('M j, Y'));
|
||||
$reldays = ($time - $today)/86400;
|
||||
|
||||
if ($reldays >= 0 && $reldays < 1)
|
||||
return 'today';
|
||||
else if ($reldays >= 1 && $reldays < 2)
|
||||
return 'tomorrow';
|
||||
else if ($reldays >= -1 && $reldays < 0)
|
||||
return 'yesterday';
|
||||
|
||||
if (abs($reldays) < 7) {
|
||||
if ($reldays > 0) {
|
||||
$reldays = floor($reldays);
|
||||
return 'in ' . $reldays . ' day' . ($reldays != 1 ? 's' : '');
|
||||
} else {
|
||||
$reldays = abs(floor($reldays));
|
||||
return $reldays . ' day' . ($reldays != 1 ? 's' : '') . ' ago';
|
||||
}
|
||||
}
|
||||
if (abs($reldays) < 182)
|
||||
return date('l, F j',$time ? $time : time());
|
||||
else
|
||||
return date('l, F j, Y',$time ? $time : time());
|
||||
}
|
||||
|
||||
static function relative_datetime($time) {
|
||||
$date = self::relative_date($time);
|
||||
|
||||
if ($date === 'today')
|
||||
return self::relative_time($time);
|
||||
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultizie php funciton as Filters */
|
||||
h2o::addFilter(array('md5', 'sha1', 'numberformat'=>'number_format', 'wordwrap', 'trim', 'upper' => 'strtoupper', 'lower' => 'strtolower'));
|
||||
|
||||
/* Add filter collections */
|
||||
h2o::addFilter(array('CoreFilters', 'StringFilters', 'NumberFilters', 'DatetimeFilters', 'HtmlFilters'));
|
||||
|
||||
/* Alias default to set_default */
|
||||
h2o::addFilter('default', array('CoreFilters', 'set_default'));
|
||||
|
||||
?>
|
||||
229
h2o/loaders.php
229
h2o/loaders.php
|
|
@ -1,229 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* @author taylor.luk
|
||||
* @todo FileLoader need more test coverage
|
||||
* @package h2o.filters
|
||||
*/
|
||||
class H2o_Loader {
|
||||
public $parser;
|
||||
public $runtime;
|
||||
public $cached = false;
|
||||
protected $cache = false;
|
||||
public $searchpath = false;
|
||||
|
||||
function read($filename) {}
|
||||
function cache_read($file, $object, $ttl = 3600) {}
|
||||
}
|
||||
|
||||
class H2o_File_Loader extends H2o_Loader {
|
||||
|
||||
function __construct($searchpath, $options = array()) {
|
||||
if (is_file($searchpath)) {
|
||||
$searthpath = dirname($searchpath).DS;
|
||||
}
|
||||
if (!is_dir($searchpath))
|
||||
throw new TemplateNotFound($filename);
|
||||
|
||||
$this->searchpath = realpath($searchpath) . DS;
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
function setOptions($options = array()) {
|
||||
if (isset($options['cache']) && $options['cache']) {
|
||||
$this->cache = h2o_cache($options);
|
||||
}
|
||||
}
|
||||
|
||||
function read($filename) {
|
||||
if (!is_file($filename))
|
||||
$filename = $this->searchpath . $filename;
|
||||
|
||||
if (is_file($filename)) {
|
||||
$source = file_get_contents($filename);
|
||||
return $this->runtime->parse($source);
|
||||
} else {
|
||||
throw new TemplateNotFound($filename);
|
||||
}
|
||||
}
|
||||
|
||||
function read_cache($filename) {
|
||||
if (!$this->cache)
|
||||
return $this->read($filename);
|
||||
|
||||
if (!is_file($filename))
|
||||
$filename = $this->searchpath . $filename;
|
||||
|
||||
$filename = realpath($filename);
|
||||
$cache = md5($filename);
|
||||
$object = $this->cache->read($cache);
|
||||
$this->cached = $object && !$this->expired($object);
|
||||
|
||||
if (!$this->cached) {
|
||||
$nodelist = $this->read($filename);
|
||||
$object = (object) array(
|
||||
'filename' => $filename,
|
||||
'content' => serialize($nodelist),
|
||||
'created' => time(),
|
||||
'templates' => $nodelist->parser->storage['templates'],
|
||||
'included' => $nodelist->parser->storage['included'] + array_values(h2o::$extensions)
|
||||
);
|
||||
$this->cache->write($cache, $object);
|
||||
} else {
|
||||
foreach($object->included as $ext => $file) {
|
||||
include_once (h2o::$extensions[$ext] = $file);
|
||||
}
|
||||
}
|
||||
return unserialize($object->content);
|
||||
}
|
||||
|
||||
function flush_cache() {
|
||||
$this->cache->flush();
|
||||
}
|
||||
|
||||
function expired($object) {
|
||||
if (!$object) return false;
|
||||
|
||||
$files = array_merge(array($object->filename), $object->templates);
|
||||
foreach ($files as $file) {
|
||||
if (!is_file($file))
|
||||
$file = $this->searchpath.$file;
|
||||
|
||||
if ($object->created < filemtime($file))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function file_loader($file) {
|
||||
return new H2o_File_Loader($file);
|
||||
}
|
||||
|
||||
class H2o_Hash_Loader {
|
||||
|
||||
function __construct($scope, $options = array()) {
|
||||
$this->scope = $scope;
|
||||
}
|
||||
|
||||
function setOptions() {}
|
||||
|
||||
function read($file) {
|
||||
if (!isset($this->scope[$file]))
|
||||
throw new TemplateNotFound;
|
||||
return $this->runtime->parse($this->scope[$file], $file);
|
||||
}
|
||||
|
||||
function read_cache($file) {
|
||||
return $this->read($file);
|
||||
}
|
||||
}
|
||||
|
||||
function hash_loader($hash = array()) {
|
||||
return new H2o_Hash_Loader($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache subsystem
|
||||
*
|
||||
*/
|
||||
function h2o_cache($options = array()) {
|
||||
$type = $options['cache'];
|
||||
$className = "H2o_".ucwords($type)."_Cache";
|
||||
|
||||
if (class_exists($className, false)) {
|
||||
return new $className($options);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class H2o_File_Cache {
|
||||
var $ttl = 3600;
|
||||
var $prefix = 'h2o_';
|
||||
|
||||
function __construct($options = array()) {
|
||||
if (isset($options['cache_dir']) && is_writable($options['cache_dir'])) {
|
||||
$path = $options['cache_dir'];
|
||||
} else {
|
||||
$path = dirname($tmp = tempnam(uniqid(rand(), true), ''));
|
||||
|
||||
if (file_exists($tmp)) unlink($tmp);
|
||||
}
|
||||
if (isset($options['cache_ttl'])) {
|
||||
$this->ttl = $options['cache_ttl'];
|
||||
}
|
||||
if(isset($options['cache_prefix'])) {
|
||||
$this->prefix = $options['cache_prefix'];
|
||||
}
|
||||
|
||||
$this->path = realpath($path). DS;
|
||||
}
|
||||
|
||||
function read($filename) {
|
||||
if (!file_exists($this->path . $this->prefix. $filename))
|
||||
return false;
|
||||
|
||||
$content = file_get_contents($this->path . $this->prefix. $filename);
|
||||
$expires = (int)substr($content, 0, 10);
|
||||
|
||||
if (time() >= $expires)
|
||||
return false;
|
||||
return unserialize(trim(substr($content, 10)));
|
||||
}
|
||||
|
||||
function write($filename, &$object) {
|
||||
$expires = time() + $this->ttl;
|
||||
$content = $expires . serialize($object);
|
||||
return file_put_contents($this->path . $this->prefix. $filename, $content);
|
||||
}
|
||||
|
||||
function flush() {
|
||||
foreach (glob($this->path. $this->prefix. '*') as $file) {
|
||||
@unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class H2o_Apc_Cache {
|
||||
var $ttl = 3600;
|
||||
var $prefix = 'h2o_';
|
||||
|
||||
function __construct($options = array()) {
|
||||
if (!function_exists('apc_add'))
|
||||
throw new Exception('APC extension needs to be loaded to use APC cache');
|
||||
|
||||
if (isset($options['cache_ttl'])) {
|
||||
$this->ttl = $options['cache_ttl'];
|
||||
}
|
||||
if(isset($options['cache_prefix'])) {
|
||||
$this->prefix = $options['cache_prefix'];
|
||||
}
|
||||
}
|
||||
|
||||
function read($filename) {
|
||||
return apc_fetch($this->prefix.$filename);
|
||||
}
|
||||
|
||||
function write($filename, $object) {
|
||||
return apc_store($this->prefix.$filename, $object, $this->ttl);
|
||||
}
|
||||
|
||||
function flush() {
|
||||
return apc_clear_cache('user');
|
||||
}
|
||||
}
|
||||
|
||||
class H2o_Memcache_Cache {
|
||||
function __construct($scope, $options = array()) {
|
||||
}
|
||||
|
||||
function read($filename) {
|
||||
}
|
||||
|
||||
function write($filename, $content) {
|
||||
}
|
||||
|
||||
function flush() {}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package h2o.nodes
|
||||
*/
|
||||
/*
|
||||
Nodes
|
||||
*/
|
||||
|
||||
class H2o_Node {
|
||||
var $position;
|
||||
function __construct($argstring) {}
|
||||
|
||||
function render($context, $stream) {}
|
||||
}
|
||||
|
||||
class NodeList extends H2o_Node implements IteratorAggregate {
|
||||
var $parser;
|
||||
var $list;
|
||||
|
||||
function __construct(&$parser, $initial = null, $position = 0) {
|
||||
$this->parser = $parser;
|
||||
if (is_null($initial))
|
||||
$initial = array();
|
||||
$this->list = $initial;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
foreach($this->list as $node) {
|
||||
$node->render($context, $stream);
|
||||
}
|
||||
}
|
||||
|
||||
function append($node) {
|
||||
array_push($this->list, $node);
|
||||
}
|
||||
|
||||
function extend($nodes) {
|
||||
array_merge($this->list, $nodes);
|
||||
}
|
||||
|
||||
function getLength() {
|
||||
return count($this->list);
|
||||
}
|
||||
|
||||
function getIterator() {
|
||||
return new ArrayIterator( $this->list );
|
||||
}
|
||||
}
|
||||
|
||||
class VariableNode extends H2o_Node {
|
||||
private $filters = array();
|
||||
var $variable;
|
||||
|
||||
function __construct($variable, $filters, $position = 0) {
|
||||
if (!empty($filters))
|
||||
$this->filters = $filters;
|
||||
$this->variable = $variable;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$value = $context->resolve($this->variable);
|
||||
$value = $context->escape($value, $this->variable);
|
||||
$stream->write($value);
|
||||
}
|
||||
}
|
||||
|
||||
class CommentNode extends H2o_Node {}
|
||||
|
||||
class TextNode extends H2o_Node {
|
||||
var $content;
|
||||
function __construct($content, $position = 0) {
|
||||
$this->content = $content;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$stream->write($this->content);
|
||||
}
|
||||
|
||||
function is_blank() {
|
||||
return strlen(trim($this->content));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
291
h2o/parser.php
291
h2o/parser.php
|
|
@ -1,291 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package h2o.parser
|
||||
*/
|
||||
class H2o_Lexer {
|
||||
function __construct($options = array()) {
|
||||
$this->options = $options;
|
||||
|
||||
if ($this->options['TRIM_TAGS'])
|
||||
$trim = '(?:\r?\n)?';
|
||||
|
||||
$this->pattern = ('/\G(.*?)(?:' .
|
||||
preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
|
||||
preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
|
||||
preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
|
||||
);
|
||||
}
|
||||
|
||||
function tokenize($source) {
|
||||
$result = new TokenStream;
|
||||
$pos = 0;
|
||||
$matches = array();
|
||||
preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);
|
||||
|
||||
foreach ($matches as $match) {
|
||||
if ($match[1])
|
||||
$result->feed('text', $match[1], $pos);
|
||||
$tagpos = $pos + strlen($match[1]);
|
||||
if ($match[2])
|
||||
$result->feed('block', trim($match[2]), $tagpos);
|
||||
elseif ($match[3])
|
||||
$result->feed('variable', trim($match[3]), $tagpos);
|
||||
elseif ($match[4])
|
||||
$result->feed('comment', trim($match[4]), $tagpos);
|
||||
$pos += strlen($match[0]);
|
||||
}
|
||||
if ($pos < strlen($source)){
|
||||
$result->feed('text', substr($source, $pos), $pos);
|
||||
}
|
||||
$result->close();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
class H2o_Parser {
|
||||
var $first;
|
||||
var $storage = array();
|
||||
var $filename;
|
||||
var $runtime;
|
||||
|
||||
function __construct($source, $filename, $runtime, $options) {
|
||||
$this->options = $options;
|
||||
//$this->source = $source;
|
||||
$this->runtime = $runtime;
|
||||
$this->filename = $filename;
|
||||
$this->first = true;
|
||||
|
||||
$this->lexer = new H2o_Lexer($options);
|
||||
$this->tokenstream = $this->lexer->tokenize($source);
|
||||
$this->storage = array(
|
||||
'blocks' => array(),
|
||||
'templates' => array(),
|
||||
'included' => array()
|
||||
);
|
||||
}
|
||||
|
||||
function &parse() {
|
||||
$until = func_get_args();
|
||||
$nodelist = new NodeList($this);
|
||||
while($token = $this->tokenstream->next()) {
|
||||
//$token = $this->tokenstream->current();
|
||||
switch($token->type) {
|
||||
case 'text' :
|
||||
$node = new TextNode($token->content, $token->position);
|
||||
break;
|
||||
case 'variable' :
|
||||
$args = H2o_Parser::parseArguments($token->content, $token->position);
|
||||
$variable = array_shift($args);
|
||||
$filters = $args;
|
||||
$node = new VariableNode($variable, $filters, $token->position);
|
||||
break;
|
||||
case 'comment' :
|
||||
$node = new CommentNode($token->content);
|
||||
break;
|
||||
case 'block' :
|
||||
if (in_array($token->content, $until)) {
|
||||
$this->token = $token;
|
||||
return $nodelist;
|
||||
}
|
||||
@list($name, $args) = preg_split('/\s+/',$token->content, 2);
|
||||
$node = H2o::createTag($name, $args, $this, $token->position);
|
||||
$this->token = $token;
|
||||
}
|
||||
$this->searching = join(',',$until);
|
||||
$this->first = false;
|
||||
$nodelist->append($node);
|
||||
}
|
||||
|
||||
if ($until) {
|
||||
throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
|
||||
}
|
||||
return $nodelist;
|
||||
}
|
||||
|
||||
function skipTo($until) {
|
||||
$this->parse($until);
|
||||
return null;
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
static function parseArguments($source = null, $fpos = 0){
|
||||
$parser = new ArgumentLexer($source, $fpos);
|
||||
$result = array();
|
||||
$current_buffer = &$result;
|
||||
$filter_buffer = array();
|
||||
$tokens = $parser->parse();
|
||||
foreach ($tokens as $token) {
|
||||
list($token, $data) = $token;
|
||||
if ($token == 'filter_start') {
|
||||
$filter_buffer = array();
|
||||
$current_buffer = &$filter_buffer;
|
||||
}
|
||||
elseif ($token == 'filter_end') {
|
||||
if (count($filter_buffer)) {
|
||||
|
||||
$i = count($result)-1;
|
||||
if ( is_array($result[$i]) ) $result[$i]['filters'][] = $filter_buffer;
|
||||
else $result[$i] = array(0 => $result[$i], 'filters' => array($filter_buffer));
|
||||
}
|
||||
$current_buffer = &$result;
|
||||
}
|
||||
elseif ($token == 'boolean') {
|
||||
$current_buffer[] = ($data === 'true'? true : false);
|
||||
}
|
||||
elseif ($token == 'name') {
|
||||
$current_buffer[] = symbol($data);
|
||||
}
|
||||
elseif ($token == 'number' || $token == 'string') {
|
||||
$current_buffer[] = $data;
|
||||
}
|
||||
elseif ($token == 'named_argument') {
|
||||
$last = $current_buffer[count($current_buffer) - 1];
|
||||
if (!is_array($last))
|
||||
$current_buffer[] = array();
|
||||
|
||||
$namedArgs =& $current_buffer[count($current_buffer) - 1];
|
||||
list($name,$value) = array_map('trim', explode(':', $data, 2));
|
||||
|
||||
# if argument value is variable mark it
|
||||
$value = self::parseArguments($value);
|
||||
$namedArgs[$name] = $value[0];
|
||||
}
|
||||
elseif( $token == 'operator') {
|
||||
$current_buffer[] = array('operator'=>$data);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
class H2O_RE {
|
||||
static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number, $string, $i18n_string, $name, $named_args;
|
||||
|
||||
static function init() {
|
||||
$r = 'strip_regex';
|
||||
|
||||
self::$whitespace = '/\s+/m';
|
||||
self::$parentheses = '/\(|\)/m';
|
||||
self::$filter_end = '/;/';
|
||||
self::$boolean = '/true|false/';
|
||||
self::$seperator = '/,/';
|
||||
self::$pipe = '/\|/';
|
||||
self::$operator = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
|
||||
self::$number = '/\d+(\.\d*)?/';
|
||||
self::$name = '/[a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
|
||||
|
||||
self::$string = '/(?:
|
||||
"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | # Double Quote string
|
||||
\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
|
||||
)/xsm';
|
||||
self::$i18n_string = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";
|
||||
|
||||
self::$named_args = "{
|
||||
({$r(self::$name)})(?:{$r(self::$whitespace)})?
|
||||
:
|
||||
(?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
|
||||
}x";
|
||||
}
|
||||
}
|
||||
H2O_RE::init();
|
||||
|
||||
class ArgumentLexer {
|
||||
private $source;
|
||||
private $match;
|
||||
private $pos = 0, $fpos, $eos;
|
||||
private $operator_map = array(
|
||||
'!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
|
||||
);
|
||||
|
||||
function __construct($source, $fpos = 0){
|
||||
if (!is_null($source))
|
||||
$this->source = $source;
|
||||
$this->fpos=$fpos;
|
||||
}
|
||||
|
||||
function parse(){
|
||||
$result = array();
|
||||
$filtering = false;
|
||||
while (!$this->eos()) {
|
||||
$this->scan(H2O_RE::$whitespace);
|
||||
if (!$filtering) {
|
||||
if ($this->scan(H2O_RE::$operator)){
|
||||
$operator = trim($this->match);
|
||||
if(isset($this->operator_map[$operator]))
|
||||
$operator = $this->operator_map[$operator];
|
||||
$result[] = array('operator', $operator);
|
||||
}
|
||||
elseif ($this->scan(H2O_RE::$boolean))
|
||||
$result[] = array('boolean', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$named_args))
|
||||
$result[] = array('named_argument', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$name))
|
||||
$result[] = array('name', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$pipe)) {
|
||||
$filtering = true;
|
||||
$result[] = array('filter_start', $this->match);
|
||||
}
|
||||
elseif ($this->scan(H2O_RE::$seperator))
|
||||
$result[] = array('separator', null);
|
||||
elseif ($this->scan(H2O_RE::$i18n_string))
|
||||
$result[] = array('string', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$number))
|
||||
$result[] = array('number', $this->match);
|
||||
else
|
||||
throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
|
||||
}
|
||||
else {
|
||||
// parse filters, with chaining and ";" as filter end character
|
||||
if ($this->scan(H2O_RE::$pipe)) {
|
||||
$result[] = array('filter_end', null);
|
||||
$result[] = array('filter_start', null);
|
||||
}
|
||||
elseif ($this->scan(H2O_RE::$seperator))
|
||||
$result[] = array('separator', null);
|
||||
elseif ($this->scan(H2O_RE::$filter_end)) {
|
||||
$result[] = array('filter_end', null);
|
||||
$filtering = false;
|
||||
}
|
||||
elseif ($this->scan(H2O_RE::$boolean))
|
||||
$result[] = array('boolean', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$named_args))
|
||||
$result[] = array('named_argument', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$name))
|
||||
$result[] = array('name', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$i18n_string))
|
||||
$result[] = array('string', $this->match);
|
||||
elseif ($this->scan(H2O_RE::$number))
|
||||
$result[] = array('number', $this->match);
|
||||
else
|
||||
throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
|
||||
}
|
||||
}
|
||||
// if we are still in the filter state, we add a filter_end token.
|
||||
if ($filtering)
|
||||
$result[] = array('filter_end', null);
|
||||
return $result;
|
||||
}
|
||||
|
||||
# String scanner
|
||||
function scan($regexp) {
|
||||
if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
|
||||
$this->match = $match[0];
|
||||
$this->pos += strlen($this->match);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function eos() {
|
||||
return $this->pos >= strlen($this->source);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the position in the template
|
||||
*/
|
||||
function getPosition() {
|
||||
return $this->fpos + $this->pos;
|
||||
}
|
||||
}
|
||||
?>
|
||||
436
h2o/tags.php
436
h2o/tags.php
|
|
@ -1,436 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* @author taylor.luk
|
||||
* @todo tags need more test coverage
|
||||
* @package h2o.tags
|
||||
*/
|
||||
|
||||
/**
|
||||
* ifchanged tag
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* Variable mode
|
||||
* {% ifchanged data.date %}...{% endifchanged %}
|
||||
*
|
||||
* Lazy mode *not implemented in h2o yet
|
||||
* {% ifchanged %}...{{ data.date }}...{% endifchanged %}
|
||||
*
|
||||
*/
|
||||
class IfChanged_Tag extends H2o_Node {
|
||||
private $nodelist_true;
|
||||
private $nodelist_false;
|
||||
private $_varlist = null;
|
||||
private $_last_seen = null;
|
||||
|
||||
function __construct($argstring, $parser, $position = 0) {
|
||||
$this->nodelist_true = $parser->parse('endifchanged', 'else');
|
||||
|
||||
if ($parser->token->content === 'else')
|
||||
$this->nodelist_false = $parser->parse('endifchanged');
|
||||
|
||||
$this->_varlist = current(H2o_Parser::parseArguments($argstring));
|
||||
|
||||
if (!$this->_varlist)
|
||||
throw new TemplateSyntaxError('H2o doesn\'t support lazy ifchanged yet. Please, supply a variable.');
|
||||
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
|
||||
if ($this->_varlist) {
|
||||
$compare_to = $context->resolve($this->_varlist);
|
||||
} else {
|
||||
/**
|
||||
* @todo Rendering method $this->nodelist_true->render() should return a result.
|
||||
* Further more $compare_to variable should be set to this result.
|
||||
*/
|
||||
$compare_to = '';
|
||||
}
|
||||
|
||||
if ($compare_to != $this->_last_seen) {
|
||||
$this->_last_seen = $compare_to;
|
||||
$this->nodelist_true->render($context, $stream);
|
||||
} elseif ($this->nodelist_false) {
|
||||
$this->nodelist_false->render($context, $stream);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class If_Tag extends H2o_Node {
|
||||
private $body;
|
||||
private $else;
|
||||
private $negate;
|
||||
|
||||
function __construct($argstring, $parser, $position = 0) {
|
||||
if (preg_match('/\s(and|or)\s/', $argstring))
|
||||
throw new TemplateSyntaxError('H2o doesn\'t support multiple expressions');
|
||||
|
||||
$this->body = $parser->parse('endif', 'else');
|
||||
|
||||
if ($parser->token->content === 'else')
|
||||
$this->else = $parser->parse('endif');
|
||||
|
||||
$this->args = H2o_Parser::parseArguments($argstring);
|
||||
|
||||
$first = current($this->args);
|
||||
if (isset($first['operator']) && $first['operator'] === 'not') {
|
||||
array_shift($this->args);
|
||||
$this->negate = true;
|
||||
}
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
if ($this->test($context))
|
||||
$this->body->render($context, $stream);
|
||||
elseif ($this->else)
|
||||
$this->else->render($context, $stream);
|
||||
}
|
||||
|
||||
function test($context) {
|
||||
$test = Evaluator::exec($this->args, $context);
|
||||
return $this->negate? !$test : $test;
|
||||
}
|
||||
}
|
||||
|
||||
class For_Tag extends H2o_Node {
|
||||
public $position;
|
||||
private $iteratable, $key, $item, $body, $else, $limit, $reversed;
|
||||
private $syntax = '{
|
||||
([a-zA-Z][a-zA-Z0-9-_]*)(?:,\s?([a-zA-Z][a-zA-Z0-9-_]*))?
|
||||
\s+in\s+
|
||||
([a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*)\s* # Iteratable name
|
||||
(?:limit\s*:\s*(\d+))?\s*
|
||||
(reversed)? # Reverse keyword
|
||||
}x';
|
||||
|
||||
function __construct($argstring, $parser, $position) {
|
||||
if (!preg_match($this->syntax, $argstring, $match))
|
||||
throw new TemplateSyntaxError("Invalid for loop syntax ");
|
||||
|
||||
$this->body = $parser->parse('endfor', 'else');
|
||||
|
||||
if ($parser->token->content === 'else')
|
||||
$this->else = $parser->parse('endfor');
|
||||
|
||||
@list(,$this->key, $this->item, $this->iteratable, $this->limit, $this->reversed) = $match;
|
||||
|
||||
if ($this->limit)
|
||||
$this->limit = (int) $this->limit;
|
||||
|
||||
# Swap value if no key found
|
||||
if (!$this->item) {
|
||||
list($this->key, $this->item) = array($this->item, $this->key);
|
||||
}
|
||||
$this->iteratable = symbol($this->iteratable);
|
||||
$this->reversed = (bool) $this->reversed;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$iteratable = $context->resolve($this->iteratable);
|
||||
|
||||
if ($this->reversed)
|
||||
$iteratable = array_reverse($iteratable);
|
||||
|
||||
if ($this->limit)
|
||||
$iteratable = array_slice($iteratable, 0, $this->limit);
|
||||
|
||||
$length = count($iteratable);
|
||||
|
||||
if ($length) {
|
||||
$parent = $context['loop'];
|
||||
$context->push();
|
||||
$rev_count = $is_even = $idx = 0;
|
||||
foreach($iteratable as $key => $value) {
|
||||
$is_even = $idx % 2;
|
||||
$rev_count = $length - $idx;
|
||||
|
||||
if ($this->key) {
|
||||
$context[$this->key] = $key;
|
||||
}
|
||||
$context[$this->item] = $value;
|
||||
$context['loop'] = array(
|
||||
'parent' => $parent,
|
||||
'first' => $idx === 0,
|
||||
'last' => $rev_count === 1,
|
||||
'odd' => !$is_even,
|
||||
'even' => $is_even,
|
||||
'length' => $length,
|
||||
'counter' => $idx + 1,
|
||||
'counter0' => $idx,
|
||||
'revcounter' => $rev_count,
|
||||
'revcounter0' => $rev_count - 1
|
||||
);
|
||||
$this->body->render($context, $stream);
|
||||
++$idx;
|
||||
}
|
||||
$context->pop();
|
||||
} elseif ($this->else)
|
||||
$this->else->render($context, $stream);
|
||||
}
|
||||
}
|
||||
|
||||
class Block_Tag extends H2o_Node {
|
||||
public $name;
|
||||
public $position;
|
||||
public $stack;
|
||||
private $syntax = '/^[a-zA-Z_][a-zA-Z0-9_-]*$/';
|
||||
|
||||
function __construct($argstring, $parser, $position) {
|
||||
if (!preg_match($this->syntax, $argstring))
|
||||
throw new TemplateSyntaxError('Block tag expects a name, example: block [content]');
|
||||
|
||||
$this->name = $argstring;
|
||||
|
||||
if (isset($parser->storage['blocks'][$this->name]))
|
||||
throw new TemplateSyntaxError('Block name exists, Please select a different block name');
|
||||
|
||||
$this->filename = $parser->filename;
|
||||
$this->stack = array($parser->parse('endblock', "endblock {$this->name}"));
|
||||
|
||||
$parser->storage['blocks'][$this->name] = $this;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
function addLayer(&$nodelist) {
|
||||
$nodelist->parent = $this;
|
||||
array_push($this->stack, $nodelist);
|
||||
}
|
||||
|
||||
function render($context, $stream, $index = 1) {
|
||||
$key = count($this->stack) - $index;
|
||||
|
||||
if (isset($this->stack[$key])) {
|
||||
$context->push();
|
||||
$context['block'] = new BlockContext($this, $context, $index);
|
||||
$this->stack[$key]->render($context, $stream);
|
||||
$context->pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Extends_Tag extends H2o_Node {
|
||||
public $filename;
|
||||
public $position;
|
||||
public $nodelist;
|
||||
private $syntax = '/^["\'](.*?)["\']$/';
|
||||
|
||||
function __construct($argstring, $parser, $position = 0) {
|
||||
if (!$parser->first)
|
||||
throw new TemplateSyntaxError('extends must be first in file');
|
||||
|
||||
if (!preg_match($this->syntax, $argstring))
|
||||
throw new TemplatesyntaxError('filename must be quoted');
|
||||
|
||||
$this->filename = stripcslashes(substr($argstring, 1, -1));
|
||||
|
||||
# Parse the current template
|
||||
$parser->parse();
|
||||
|
||||
# Parse parent template
|
||||
$this->nodelist = $parser->runtime->loadSubTemplate($this->filename, $parser->options);
|
||||
$parser->storage['templates'] = array_merge(
|
||||
$parser->storage['templates'], $this->nodelist->parser->storage['templates']
|
||||
);
|
||||
$parser->storage['templates'][] = $this->filename;
|
||||
|
||||
if (!isset($this->nodelist->parser->storage['blocks']) || !isset($parser->storage['blocks']))
|
||||
return ;
|
||||
|
||||
# Blocks of parent template
|
||||
$blocks =& $this->nodelist->parser->storage['blocks'];
|
||||
|
||||
# Push child blocks on top of parent blocks
|
||||
foreach($parser->storage['blocks'] as $name => &$block) {
|
||||
if (isset($blocks[$name])) {
|
||||
$blocks[$name]->addLayer($block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$this->nodelist->render($context, $stream);
|
||||
}
|
||||
}
|
||||
|
||||
class Include_Tag extends H2o_Node {
|
||||
private $nodelist;
|
||||
private $syntax = '/^["\'](.*?)["\']$/';
|
||||
|
||||
function __construct($argstring, $parser, $position = 0) {
|
||||
if (!preg_match($this->syntax, $argstring))
|
||||
throw new TemplateSyntaxError();
|
||||
|
||||
$this->filename = stripcslashes(substr($argstring, 1, -1));
|
||||
$this->nodelist = $parser->runtime->loadSubTemplate($this->filename, $parser->options);
|
||||
$parser->storage['templates'] = array_merge(
|
||||
$this->nodelist->parser->storage['templates'], $parser->storage['templates']
|
||||
);
|
||||
$parser->storage['templates'][] = $this->filename;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$this->nodelist->render($context, $stream);
|
||||
}
|
||||
}
|
||||
|
||||
class With_Tag extends H2o_Node {
|
||||
public $position;
|
||||
private $variable, $shortcut;
|
||||
private $nodelist;
|
||||
private $syntax = '/^([\w]+(:?\.[\w\d]+)*)\s+as\s+([\w]+(:?\.[\w\d]+)?)$/';
|
||||
|
||||
function __construct($argstring, $parser, $position = 0) {
|
||||
if (!preg_match($this->syntax, $argstring, $matches))
|
||||
throw new TemplateSyntaxError('Invalid with tag syntax');
|
||||
|
||||
# extract the long name and shortcut
|
||||
list(,$this->variable, ,$this->shortcut) = $matches;
|
||||
$this->nodelist = $parser->parse('endwith');
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$variable = $context->getVariable($this->variable);
|
||||
|
||||
$context->push(array($this->shortcut => $variable));
|
||||
$this->nodelist->render($context, $stream);
|
||||
$context->pop();
|
||||
}
|
||||
}
|
||||
|
||||
class Cycle_Tag extends H2o_Node {
|
||||
private $uid;
|
||||
private $sequence;
|
||||
|
||||
function __construct($argstring, $parser, $pos) {
|
||||
$args = h2o_parser::parseArguments($argstring);
|
||||
|
||||
if (count($args) < 2) {
|
||||
throw new Exception('Cycle tag require more than two items');
|
||||
}
|
||||
$this->sequence = $args;
|
||||
$this->uid = '__cycle__'.$pos;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
if (!is_null($item = $context->getVariable($this->uid))) {
|
||||
$item = ($item + 1) % count($this->sequence);
|
||||
} else {
|
||||
$item = 0;
|
||||
}
|
||||
$stream->write($context->resolve($this->sequence[$item]));
|
||||
$context->set($this->uid, $item);
|
||||
}
|
||||
}
|
||||
|
||||
class Load_Tag extends H2o_Node {
|
||||
public $position;
|
||||
private $searchpath = array(H2O_ROOT);
|
||||
private $extension;
|
||||
|
||||
function __construct($argstring, $parser, $pos = 0) {
|
||||
$this->extension = stripcslashes(preg_replace("/^[\"'](.*)[\"']$/", "$1", $argstring));
|
||||
|
||||
if ($parser->runtime->searchpath)
|
||||
$this->appendPath($parser->runtime->searchpath);
|
||||
|
||||
$parser->storage['included'][$this->extension] = $file = $this->load();
|
||||
$this->position = $pos;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
function appendPath($path) {
|
||||
$this->searchpath[] = $path;
|
||||
}
|
||||
|
||||
private function load() {
|
||||
if (isset(h2o::$extensions[$this->extension])) {
|
||||
return true;
|
||||
}
|
||||
foreach($this->searchpath as $path) {
|
||||
$file = $path.'ext'.DS.$this->extension.'.php';
|
||||
if (is_file($file)) {
|
||||
h2o::load($this->extension, $file);
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
throw new H2o_Error(
|
||||
"Extension: {$this->extension} cannot be loaded, please confirm it exist in extension path"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Debug_Tag extends H2o_Node {
|
||||
private $argument;
|
||||
function __construct($argstring, $parser, $pos = 0) {
|
||||
$this->argument = $argstring;
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
if ($this->argument) {
|
||||
$object = $context->resolve(symbol($this->argument));
|
||||
} else {
|
||||
$object = $context->scopes[0];
|
||||
}
|
||||
$output = "<pre>". print_r($object, true). "</pre>";
|
||||
$stream->write($output);
|
||||
}
|
||||
}
|
||||
|
||||
class Now_Tag extends H2o_Node {
|
||||
function __construct($argstring, $parser, $pos=0) {
|
||||
$this->format = $argstring;
|
||||
if (!$this->format) {
|
||||
$this->format = "D M j G:i:s T Y";
|
||||
}
|
||||
}
|
||||
|
||||
function render($contxt, $stream) {
|
||||
sleep(1);
|
||||
$time = date($this->format);
|
||||
$stream->write($time);
|
||||
}
|
||||
}
|
||||
|
||||
class Autoescape_Tag extends H2o_Node {
|
||||
protected $enable;
|
||||
|
||||
function __construct($argstring, $parser, $pos = 0) {
|
||||
if ($argstring === 'on')
|
||||
$this->enable = true;
|
||||
elseif ($argstring === 'off')
|
||||
$this->enable = false;
|
||||
else throw new H2o_Error(
|
||||
"Invalid syntax : autoescape on|off "
|
||||
);
|
||||
}
|
||||
|
||||
function render($context, $stream) {
|
||||
$context->autoescape = $this->enable;
|
||||
}
|
||||
}
|
||||
|
||||
class Csrf_token_Tag extends H2o_Node {
|
||||
function render($context, $stream) {
|
||||
$token = "";
|
||||
if (isset($_COOKIE["csrftoken"]))
|
||||
$token = $_COOKIE["csrftoken"];
|
||||
else {
|
||||
global $SECRET_KEY;
|
||||
if (defined('SECRET_KEY'))
|
||||
$token = md5(mt_rand() . SECRET_KEY);
|
||||
else
|
||||
$token = md5(mt_rand());
|
||||
}
|
||||
setcookie("csrftoken", $token, time()+60*60*24*365, "/");
|
||||
$stream->write("<div style='display:none'><input type=\"hidden\" value=\"$token\" name=\"csrfmiddlewaretoken\" /></div>");
|
||||
}
|
||||
}
|
||||
|
||||
H2o::addTag(array('block', 'extends', 'include', 'if', 'ifchanged', 'for', 'with', 'cycle', 'load', 'debug', 'now', 'autoescape', 'csrf_token'));
|
||||
?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue