From 1223d54573e8cf7b95e6e6303e47775169b079a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A4=D1=91=D0=B4=D0=BE=D1=80=20=D0=9F=D0=BE=D0=B4=D0=BB?= =?UTF-8?q?=D0=B5=D1=81=D0=BD=D0=BE=D0=B2?= Date: Thu, 30 Jun 2016 15:07:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=BC=D0=B5=D0=BD=D1=8F=D0=B5?= =?UTF-8?q?=D0=BC=20creole=20=D0=BD=D0=B0=20pdo,=20=D1=83=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D0=BE=D1=82=20h2o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/controller/frontcontroller.php | 4 +- creole/CallableStatement.php | 135 ---- creole/Connection.php | 220 ------ creole/Creole.php | 390 ----------- creole/CreoleTypes.php | 183 ----- creole/IdGenerator.php | 57 -- creole/PreparedStatement.php | 253 ------- creole/ResultSet.php | 380 ----------- creole/ResultSetIterator.php | 113 ---- creole/SQLException.php | 105 --- creole/Statement.php | 147 ---- creole/common/ConnectionCommon.php | 258 ------- creole/common/PreparedStatementCommon.php | 640 ------------------ creole/common/ResultSetCommon.php | 447 ------------ creole/common/StatementCommon.php | 289 -------- creole/contrib/DebugConnection.php | 268 -------- .../drivers/mssql/MSSQLCallableStatement.php | 478 ------------- creole/drivers/mssql/MSSQLConnection.php | 283 -------- creole/drivers/mssql/MSSQLIdGenerator.php | 62 -- .../drivers/mssql/MSSQLPreparedStatement.php | 99 --- creole/drivers/mssql/MSSQLResultSet.php | 159 ----- creole/drivers/mssql/MSSQLStatement.php | 72 -- creole/drivers/mssql/MSSQLTypes.php | 94 --- .../mssql/metadata/MSSQLDatabaseInfo.php | 69 -- .../drivers/mssql/metadata/MSSQLTableInfo.php | 183 ----- creole/drivers/mysql/MySQLConnection.php | 290 -------- creole/drivers/mysql/MySQLIdGenerator.php | 75 -- .../drivers/mysql/MySQLPreparedStatement.php | 44 -- creole/drivers/mysql/MySQLResultSet.php | 148 ---- creole/drivers/mysql/MySQLStatement.php | 36 - creole/drivers/mysql/MySQLTypes.php | 102 --- .../mysql/metadata/MySQLDatabaseInfo.php | 66 -- .../drivers/mysql/metadata/MySQLTableInfo.php | 252 ------- creole/drivers/mysqli/MySQLiConnection.php | 243 ------- creole/drivers/mysqli/MySQLiIdGenerator.php | 96 --- .../mysqli/MySQLiPreparedStatement.php | 42 -- creole/drivers/mysqli/MySQLiResultSet.php | 173 ----- creole/drivers/mysqli/MySQLiStatement.php | 33 - .../mysqli/metadata/MySQLiDatabaseInfo.php | 61 -- .../mysqli/metadata/MySQLiTableInfo.php | 143 ---- creole/drivers/odbc/ODBCCachedResultSet.php | 218 ------ creole/drivers/odbc/ODBCConnection.php | 362 ---------- creole/drivers/odbc/ODBCIdGenerator.php | 118 ---- creole/drivers/odbc/ODBCPreparedStatement.php | 246 ------- creole/drivers/odbc/ODBCResultSet.php | 209 ------ creole/drivers/odbc/ODBCResultSetCommon.php | 188 ----- creole/drivers/odbc/ODBCStatement.php | 64 -- creole/drivers/odbc/ODBCTypes.php | 189 ------ creole/drivers/odbc/README | 90 --- .../drivers/odbc/adapters/CodeBaseAdapter.php | 73 -- creole/drivers/odbc/adapters/MySQLAdapter.php | 78 --- creole/drivers/odbc/adapters/ODBCAdapter.php | 115 ---- .../odbc/metadata/ODBCDatabaseInfo.php | 66 -- .../drivers/odbc/metadata/ODBCTableInfo.php | 141 ---- creole/drivers/oracle/OCI8Connection.php | 393 ----------- creole/drivers/oracle/OCI8IdGenerator.php | 65 -- .../drivers/oracle/OCI8PreparedStatement.php | 424 ------------ creole/drivers/oracle/OCI8ResultSet.php | 131 ---- creole/drivers/oracle/OCI8Statement.php | 34 - creole/drivers/oracle/OCI8Types.php | 88 --- .../oracle/metadata/OCI8DatabaseInfo.php | 90 --- .../drivers/oracle/metadata/OCI8TableInfo.php | 273 -------- creole/drivers/pgsql/PgSQLConnection.php | 260 ------- creole/drivers/pgsql/PgSQLIdGenerator.php | 84 --- .../drivers/pgsql/PgSQLPreparedStatement.php | 157 ----- creole/drivers/pgsql/PgSQLResultSet.php | 213 ------ .../drivers/pgsql/PgSQLResultSetIterator.php | 109 --- creole/drivers/pgsql/PgSQLStatement.php | 34 - creole/drivers/pgsql/PgSQLTypes.php | 101 --- .../pgsql/metadata/PgSQLDatabaseInfo.php | 113 ---- .../drivers/pgsql/metadata/PgSQLTableInfo.php | 423 ------------ creole/drivers/sqlite/SQLiteConnection.php | 245 ------- creole/drivers/sqlite/SQLiteIdGenerator.php | 60 -- .../sqlite/SQLitePreparedStatement.php | 61 -- creole/drivers/sqlite/SQLiteResultSet.php | 119 ---- .../sqlite/SQLiteResultSetIterator.php | 88 --- creole/drivers/sqlite/SQLiteStatement.php | 34 - creole/drivers/sqlite/SQLiteTypes.php | 108 --- .../sqlite/metadata/SQLiteDatabaseInfo.php | 64 -- .../sqlite/metadata/SQLiteTableInfo.php | 135 ---- creole/metadata/ColumnInfo.php | 232 ------- creole/metadata/DatabaseInfo.php | 206 ------ creole/metadata/ForeignKeyInfo.php | 103 --- creole/metadata/IndexInfo.php | 84 --- creole/metadata/PrimaryKeyInfo.php | 91 --- creole/metadata/TableInfo.php | 305 --------- creole/util/Blob.php | 62 -- creole/util/Clob.php | 112 --- creole/util/Lob.php | 243 ------- creole/util/sql/SQLStatementExtractor.php | 164 ----- h2o.php | 267 -------- h2o/context.php | 264 -------- h2o/datatype.php | 176 ----- h2o/errors.php | 11 - h2o/filters.php | 345 ---------- h2o/loaders.php | 229 ------- h2o/nodes.php | 88 --- h2o/parser.php | 291 -------- h2o/tags.php | 436 ------------ 99 files changed, 2 insertions(+), 16962 deletions(-) delete mode 100644 creole/CallableStatement.php delete mode 100644 creole/Connection.php delete mode 100644 creole/Creole.php delete mode 100644 creole/CreoleTypes.php delete mode 100644 creole/IdGenerator.php delete mode 100644 creole/PreparedStatement.php delete mode 100644 creole/ResultSet.php delete mode 100644 creole/ResultSetIterator.php delete mode 100644 creole/SQLException.php delete mode 100644 creole/Statement.php delete mode 100644 creole/common/ConnectionCommon.php delete mode 100644 creole/common/PreparedStatementCommon.php delete mode 100644 creole/common/ResultSetCommon.php delete mode 100644 creole/common/StatementCommon.php delete mode 100644 creole/contrib/DebugConnection.php delete mode 100644 creole/drivers/mssql/MSSQLCallableStatement.php delete mode 100644 creole/drivers/mssql/MSSQLConnection.php delete mode 100644 creole/drivers/mssql/MSSQLIdGenerator.php delete mode 100644 creole/drivers/mssql/MSSQLPreparedStatement.php delete mode 100644 creole/drivers/mssql/MSSQLResultSet.php delete mode 100644 creole/drivers/mssql/MSSQLStatement.php delete mode 100644 creole/drivers/mssql/MSSQLTypes.php delete mode 100644 creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php delete mode 100644 creole/drivers/mssql/metadata/MSSQLTableInfo.php delete mode 100644 creole/drivers/mysql/MySQLConnection.php delete mode 100644 creole/drivers/mysql/MySQLIdGenerator.php delete mode 100644 creole/drivers/mysql/MySQLPreparedStatement.php delete mode 100644 creole/drivers/mysql/MySQLResultSet.php delete mode 100644 creole/drivers/mysql/MySQLStatement.php delete mode 100644 creole/drivers/mysql/MySQLTypes.php delete mode 100644 creole/drivers/mysql/metadata/MySQLDatabaseInfo.php delete mode 100644 creole/drivers/mysql/metadata/MySQLTableInfo.php delete mode 100644 creole/drivers/mysqli/MySQLiConnection.php delete mode 100644 creole/drivers/mysqli/MySQLiIdGenerator.php delete mode 100644 creole/drivers/mysqli/MySQLiPreparedStatement.php delete mode 100644 creole/drivers/mysqli/MySQLiResultSet.php delete mode 100644 creole/drivers/mysqli/MySQLiStatement.php delete mode 100644 creole/drivers/mysqli/metadata/MySQLiDatabaseInfo.php delete mode 100644 creole/drivers/mysqli/metadata/MySQLiTableInfo.php delete mode 100644 creole/drivers/odbc/ODBCCachedResultSet.php delete mode 100644 creole/drivers/odbc/ODBCConnection.php delete mode 100644 creole/drivers/odbc/ODBCIdGenerator.php delete mode 100644 creole/drivers/odbc/ODBCPreparedStatement.php delete mode 100644 creole/drivers/odbc/ODBCResultSet.php delete mode 100644 creole/drivers/odbc/ODBCResultSetCommon.php delete mode 100644 creole/drivers/odbc/ODBCStatement.php delete mode 100644 creole/drivers/odbc/ODBCTypes.php delete mode 100644 creole/drivers/odbc/README delete mode 100644 creole/drivers/odbc/adapters/CodeBaseAdapter.php delete mode 100644 creole/drivers/odbc/adapters/MySQLAdapter.php delete mode 100644 creole/drivers/odbc/adapters/ODBCAdapter.php delete mode 100644 creole/drivers/odbc/metadata/ODBCDatabaseInfo.php delete mode 100644 creole/drivers/odbc/metadata/ODBCTableInfo.php delete mode 100644 creole/drivers/oracle/OCI8Connection.php delete mode 100644 creole/drivers/oracle/OCI8IdGenerator.php delete mode 100644 creole/drivers/oracle/OCI8PreparedStatement.php delete mode 100644 creole/drivers/oracle/OCI8ResultSet.php delete mode 100644 creole/drivers/oracle/OCI8Statement.php delete mode 100644 creole/drivers/oracle/OCI8Types.php delete mode 100644 creole/drivers/oracle/metadata/OCI8DatabaseInfo.php delete mode 100644 creole/drivers/oracle/metadata/OCI8TableInfo.php delete mode 100644 creole/drivers/pgsql/PgSQLConnection.php delete mode 100644 creole/drivers/pgsql/PgSQLIdGenerator.php delete mode 100644 creole/drivers/pgsql/PgSQLPreparedStatement.php delete mode 100644 creole/drivers/pgsql/PgSQLResultSet.php delete mode 100644 creole/drivers/pgsql/PgSQLResultSetIterator.php delete mode 100644 creole/drivers/pgsql/PgSQLStatement.php delete mode 100644 creole/drivers/pgsql/PgSQLTypes.php delete mode 100644 creole/drivers/pgsql/metadata/PgSQLDatabaseInfo.php delete mode 100644 creole/drivers/pgsql/metadata/PgSQLTableInfo.php delete mode 100644 creole/drivers/sqlite/SQLiteConnection.php delete mode 100644 creole/drivers/sqlite/SQLiteIdGenerator.php delete mode 100644 creole/drivers/sqlite/SQLitePreparedStatement.php delete mode 100644 creole/drivers/sqlite/SQLiteResultSet.php delete mode 100644 creole/drivers/sqlite/SQLiteResultSetIterator.php delete mode 100644 creole/drivers/sqlite/SQLiteStatement.php delete mode 100644 creole/drivers/sqlite/SQLiteTypes.php delete mode 100644 creole/drivers/sqlite/metadata/SQLiteDatabaseInfo.php delete mode 100644 creole/drivers/sqlite/metadata/SQLiteTableInfo.php delete mode 100644 creole/metadata/ColumnInfo.php delete mode 100644 creole/metadata/DatabaseInfo.php delete mode 100644 creole/metadata/ForeignKeyInfo.php delete mode 100644 creole/metadata/IndexInfo.php delete mode 100644 creole/metadata/PrimaryKeyInfo.php delete mode 100644 creole/metadata/TableInfo.php delete mode 100644 creole/util/Blob.php delete mode 100644 creole/util/Clob.php delete mode 100644 creole/util/Lob.php delete mode 100644 creole/util/sql/SQLStatementExtractor.php delete mode 100644 h2o.php delete mode 100644 h2o/context.php delete mode 100644 h2o/datatype.php delete mode 100644 h2o/errors.php delete mode 100644 h2o/filters.php delete mode 100644 h2o/loaders.php delete mode 100644 h2o/nodes.php delete mode 100644 h2o/parser.php delete mode 100644 h2o/tags.php diff --git a/core/controller/frontcontroller.php b/core/controller/frontcontroller.php index e3d4c2e..f6106b2 100644 --- a/core/controller/frontcontroller.php +++ b/core/controller/frontcontroller.php @@ -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); } diff --git a/creole/CallableStatement.php b/creole/CallableStatement.php deleted file mode 100644 index 05a6c3b..0000000 --- a/creole/CallableStatement.php +++ /dev/null @@ -1,135 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; - -/** - * Interface for callable statements. - * - * @author Hans Lellelid - * @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'); - -} diff --git a/creole/Connection.php b/creole/Connection.php deleted file mode 100644 index b860249..0000000 --- a/creole/Connection.php +++ /dev/null @@ -1,220 +0,0 @@ -. - */ - -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 - * @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(); - -} \ No newline at end of file diff --git a/creole/Creole.php b/creole/Creole.php deleted file mode 100644 index c48d5d6..0000000 --- a/creole/Creole.php +++ /dev/null @@ -1,390 +0,0 @@ -. - */ - -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 - * @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. - *

- * 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; - } - -} diff --git a/creole/CreoleTypes.php b/creole/CreoleTypes.php deleted file mode 100644 index c28a615..0000000 --- a/creole/CreoleTypes.php +++ /dev/null @@ -1,183 +0,0 @@ -. - */ - -/** - * Generic Creole types modeled on JDBC types. - * - * @author David Giffin - * @author Hans Lellelid - * @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. - * - * $setter = 'set' . CreoleTypes::getAffix(CreoleTypes::INTEGER); - * $stmt->$setter(1, $intval); - * // or - * $getter = 'get' . CreoleTypes::getAffix(CreoleTypes::TIMESTAMP); - * $timestamp = $rs->$getter(); - * - * @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; - } -} diff --git a/creole/IdGenerator.php b/creole/IdGenerator.php deleted file mode 100644 index c034d0c..0000000 --- a/creole/IdGenerator.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @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). - *

- * 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); - -} - diff --git a/creole/PreparedStatement.php b/creole/PreparedStatement.php deleted file mode 100644 index 8443491..0000000 --- a/creole/PreparedStatement.php +++ /dev/null @@ -1,253 +0,0 @@ -. - */ - -/** - * 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 - * - * $stmt = $conn->prepareStatement("INSERT INTO users (name, passwd) VALUES (:name, :pass)"); - * $stmt->setString(":name", $name); - * $stmt->executeUpdate(); - * - * - * 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 - * @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 null 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 null 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); - -} diff --git a/creole/ResultSet.php b/creole/ResultSet.php deleted file mode 100644 index 12df38f..0000000 --- a/creole/ResultSet.php +++ /dev/null @@ -1,380 +0,0 @@ -. - */ - -/** - * 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. - * - * - * $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) - * - * - * This class implements SPL IteratorAggregate, so you may iterate over the database results - * using foreach(): - * - * foreach($rs as $row) { - * print_r($row); // row is assoc array returned by getRow() - * } - * - * - * @author Hans Lellelid - * @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 true if success, false 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 true if success, false 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 true if cursor is on a row, false 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 true if cursor is on a row, false 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)). - * - * 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 false 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. - * - * @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 true on success or false 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 true on success or false 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'); - -} - diff --git a/creole/ResultSetIterator.php b/creole/ResultSetIterator.php deleted file mode 100644 index ba0b88e..0000000 --- a/creole/ResultSetIterator.php +++ /dev/null @@ -1,113 +0,0 @@ -. - */ - -/** - * 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: - * - * $it = $obj->getIterator(); - * for($it->rewind(); $it->valid(); $it->next()) { - * $key = $it->current(); - * $val = $it->key(); - * echo "$key = $val\n"; - * } - * unset($it); - * - * - * @author Hans Lellelid - * @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() - { - } - -} \ No newline at end of file diff --git a/creole/SQLException.php b/creole/SQLException.php deleted file mode 100644 index 523bf35..0000000 --- a/creole/SQLException.php +++ /dev/null @@ -1,105 +0,0 @@ -. - */ - -/** - * A class for handling database-related errors. - * - * @author Hans Lellelid - * @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(); - } -} \ No newline at end of file diff --git a/creole/Statement.php b/creole/Statement.php deleted file mode 100644 index a41f5bf..0000000 --- a/creole/Statement.php +++ /dev/null @@ -1,147 +0,0 @@ -. - */ - -/** - * 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 - * @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 null 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(); - -} diff --git a/creole/common/ConnectionCommon.php b/creole/common/ConnectionCommon.php deleted file mode 100644 index aec62f8..0000000 --- a/creole/common/ConnectionCommon.php +++ /dev/null @@ -1,258 +0,0 @@ -. - */ - -/** - * 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 - * @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. - * - *

- * 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); - } -} \ No newline at end of file diff --git a/creole/common/PreparedStatementCommon.php b/creole/common/PreparedStatementCommon.php deleted file mode 100644 index 35a3d6e..0000000 --- a/creole/common/PreparedStatementCommon.php +++ /dev/null @@ -1,640 +0,0 @@ -. - */ - -/** - * 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 - * @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 null. - * @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)."'"; - } - } - -} diff --git a/creole/common/ResultSetCommon.php b/creole/common/ResultSetCommon.php deleted file mode 100644 index 4fea9d9..0000000 --- a/creole/common/ResultSetCommon.php +++ /dev/null @@ -1,447 +0,0 @@ -. - */ - -/** - * 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 null if the database returned NULL - * 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. - * - * - * $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) - * - * - * @author Hans Lellelid - * @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); - } - } -} diff --git a/creole/common/StatementCommon.php b/creole/common/StatementCommon.php deleted file mode 100644 index 10df199..0000000 --- a/creole/common/StatementCommon.php +++ /dev/null @@ -1,289 +0,0 @@ -. - */ - -/** - * Class that contains common/shared functionality for Statements. - * - * @author Hans Lellelid - * @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 null 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: - *

-     *     -- SQL-defined comment, but not truly comment in Oracle
-     *  # comment in mysql
-     *  /* comment in mssql, others * /
-     *  // comment sometimes?
-     *  REM also comment ...
-     * 
- * - * 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; - } -} diff --git a/creole/contrib/DebugConnection.php b/creole/contrib/DebugConnection.php deleted file mode 100644 index d688078..0000000 --- a/creole/contrib/DebugConnection.php +++ /dev/null @@ -1,268 +0,0 @@ - - * Creole::registerDriver('*', 'creole.drivers.debug.DebugConnection'); - * - * - * 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); - } - } - -} \ No newline at end of file diff --git a/creole/drivers/mssql/MSSQLCallableStatement.php b/creole/drivers/mssql/MSSQLCallableStatement.php deleted file mode 100644 index 54825bb..0000000 --- a/creole/drivers/mssql/MSSQLCallableStatement.php +++ /dev/null @@ -1,478 +0,0 @@ -. - */ - -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 - * @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); - } - } - -} diff --git a/creole/drivers/mssql/MSSQLConnection.php b/creole/drivers/mssql/MSSQLConnection.php deleted file mode 100644 index f3bea1b..0000000 --- a/creole/drivers/mssql/MSSQLConnection.php +++ /dev/null @@ -1,283 +0,0 @@ -. - */ - - -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: - * - * ini_set('mssql.textsize', 2147483647); - * ini_set('mssql.textlimit', 2147483647); - * - * 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 - * @author Stig Bakken - * @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); - } -} \ No newline at end of file diff --git a/creole/drivers/mssql/MSSQLIdGenerator.php b/creole/drivers/mssql/MSSQLIdGenerator.php deleted file mode 100644 index cdc58e0..0000000 --- a/creole/drivers/mssql/MSSQLIdGenerator.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @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); - } - -} - diff --git a/creole/drivers/mssql/MSSQLPreparedStatement.php b/creole/drivers/mssql/MSSQLPreparedStatement.php deleted file mode 100644 index c3bba2c..0000000 --- a/creole/drivers/mssql/MSSQLPreparedStatement.php +++ /dev/null @@ -1,99 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; - -/** - * MSSQL specific PreparedStatement functions. - * - * @author Hans Lellelid - * @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; - } -} diff --git a/creole/drivers/mssql/MSSQLResultSet.php b/creole/drivers/mssql/MSSQLResultSet.php deleted file mode 100644 index 8c0b34e..0000000 --- a/creole/drivers/mssql/MSSQLResultSet.php +++ /dev/null @@ -1,159 +0,0 @@ -. - */ - -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 - * @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; - } - -} diff --git a/creole/drivers/mssql/MSSQLStatement.php b/creole/drivers/mssql/MSSQLStatement.php deleted file mode 100644 index 07a8523..0000000 --- a/creole/drivers/mssql/MSSQLStatement.php +++ /dev/null @@ -1,72 +0,0 @@ -. - */ - -require_once 'creole/common/StatementCommon.php'; -require_once 'creole/Statement.php'; - -/** - * Class that contains MSSQL functionality for Statements. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/drivers/mssql/MSSQLTypes.php b/creole/drivers/mssql/MSSQLTypes.php deleted file mode 100644 index eaa0c3a..0000000 --- a/creole/drivers/mssql/MSSQLTypes.php +++ /dev/null @@ -1,94 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; - -/** - * MSSQL types / type map. - * - * @author Hans Lellelid - * @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]; - } - -} \ No newline at end of file diff --git a/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php b/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php deleted file mode 100644 index cf90f3a..0000000 --- a/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -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. - } - -} diff --git a/creole/drivers/mssql/metadata/MSSQLTableInfo.php b/creole/drivers/mssql/metadata/MSSQLTableInfo.php deleted file mode 100644 index fffaaa8..0000000 --- a/creole/drivers/mssql/metadata/MSSQLTableInfo.php +++ /dev/null @@ -1,183 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; -require_once 'creole/metadata/TableInfo.php'; - -/** - * MSSQL implementation of TableInfo. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/drivers/mysql/MySQLConnection.php b/creole/drivers/mysql/MySQLConnection.php deleted file mode 100644 index 56f5f10..0000000 --- a/creole/drivers/mysql/MySQLConnection.php +++ /dev/null @@ -1,290 +0,0 @@ -. - */ - -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 - * @author Stig Bakken - * @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); - } - -} \ No newline at end of file diff --git a/creole/drivers/mysql/MySQLIdGenerator.php b/creole/drivers/mysql/MySQLIdGenerator.php deleted file mode 100644 index db211ae..0000000 --- a/creole/drivers/mysql/MySQLIdGenerator.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @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; - } - -} - diff --git a/creole/drivers/mysql/MySQLPreparedStatement.php b/creole/drivers/mysql/MySQLPreparedStatement.php deleted file mode 100644 index a56f4d4..0000000 --- a/creole/drivers/mysql/MySQLPreparedStatement.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; - -/** - * MySQL subclass for prepared statements. - * - * @author Hans Lellelid - * @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()); - } - -} diff --git a/creole/drivers/mysql/MySQLResultSet.php b/creole/drivers/mysql/MySQLResultSet.php deleted file mode 100644 index 9f3f580..0000000 --- a/creole/drivers/mysql/MySQLResultSet.php +++ /dev/null @@ -1,148 +0,0 @@ -. - */ - -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 - * @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); - } - } - -} diff --git a/creole/drivers/mysql/MySQLStatement.php b/creole/drivers/mysql/MySQLStatement.php deleted file mode 100644 index fbd3e24..0000000 --- a/creole/drivers/mysql/MySQLStatement.php +++ /dev/null @@ -1,36 +0,0 @@ -. - */ - -require_once 'creole/Statement.php'; -require_once 'creole/common/StatementCommon.php'; - -/** - * MySQL Statement - * - * @author Hans Lellelid - * @author Stig Bakken - * @author Lukas Smith - * @version $Revision: 1.1 $ - * @package creole.drivers.mysql - */ -class MySQLStatement extends StatementCommon implements Statement { - -} diff --git a/creole/drivers/mysql/MySQLTypes.php b/creole/drivers/mysql/MySQLTypes.php deleted file mode 100644 index 27205e0..0000000 --- a/creole/drivers/mysql/MySQLTypes.php +++ /dev/null @@ -1,102 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; - -/** - * MySQL types / type map. - * - * @author Hans Lellelid - * @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]; - } - -} \ No newline at end of file diff --git a/creole/drivers/mysql/metadata/MySQLDatabaseInfo.php b/creole/drivers/mysql/metadata/MySQLDatabaseInfo.php deleted file mode 100644 index 0e032cc..0000000 --- a/creole/drivers/mysql/metadata/MySQLDatabaseInfo.php +++ /dev/null @@ -1,66 +0,0 @@ -. - */ - -require_once 'creole/metadata/DatabaseInfo.php'; - -/** - * MySQL implementation of DatabaseInfo. - * - * @author Hans Lellelid - * @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."); - } -} diff --git a/creole/drivers/mysql/metadata/MySQLTableInfo.php b/creole/drivers/mysql/metadata/MySQLTableInfo.php deleted file mode 100644 index 18d4127..0000000 --- a/creole/drivers/mysql/metadata/MySQLTableInfo.php +++ /dev/null @@ -1,252 +0,0 @@ -. - */ - -require_once 'creole/metadata/TableInfo.php'; - -/** - * MySQL implementation of TableInfo. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/drivers/mysqli/MySQLiConnection.php b/creole/drivers/mysqli/MySQLiConnection.php deleted file mode 100644 index 9201414..0000000 --- a/creole/drivers/mysqli/MySQLiConnection.php +++ /dev/null @@ -1,243 +0,0 @@ -. - */ - -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 - * @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); - } -} diff --git a/creole/drivers/mysqli/MySQLiIdGenerator.php b/creole/drivers/mysqli/MySQLiIdGenerator.php deleted file mode 100644 index 3db78e6..0000000 --- a/creole/drivers/mysqli/MySQLiIdGenerator.php +++ /dev/null @@ -1,96 +0,0 @@ -. - */ - -require_once 'creole/IdGenerator.php'; - -/** - * MySQLi implementation of IdGenerator. - * - * @author Sebastian Bergmann - * @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; - } -} diff --git a/creole/drivers/mysqli/MySQLiPreparedStatement.php b/creole/drivers/mysqli/MySQLiPreparedStatement.php deleted file mode 100644 index 4cfd92d..0000000 --- a/creole/drivers/mysqli/MySQLiPreparedStatement.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; - -/** - * MySQLi implementation of PreparedStatement. - * - * @author Sebastian Bergmann - * @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); - } -} diff --git a/creole/drivers/mysqli/MySQLiResultSet.php b/creole/drivers/mysqli/MySQLiResultSet.php deleted file mode 100644 index fecfd63..0000000 --- a/creole/drivers/mysqli/MySQLiResultSet.php +++ /dev/null @@ -1,173 +0,0 @@ -. - */ - -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 - * @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); - } - } -} diff --git a/creole/drivers/mysqli/MySQLiStatement.php b/creole/drivers/mysqli/MySQLiStatement.php deleted file mode 100644 index dea22b8..0000000 --- a/creole/drivers/mysqli/MySQLiStatement.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -require_once 'creole/Statement.php'; -require_once 'creole/common/StatementCommon.php'; - -/** - * MySQLi implementation of Statement. - * - * @author Sebastian Bergmann - * @version $Revision: 1.2 $ - * @package creole.drivers.mysqli - */ -class MySQLiStatement extends StatementCommon implements Statement { -} diff --git a/creole/drivers/mysqli/metadata/MySQLiDatabaseInfo.php b/creole/drivers/mysqli/metadata/MySQLiDatabaseInfo.php deleted file mode 100644 index b7b60cc..0000000 --- a/creole/drivers/mysqli/metadata/MySQLiDatabaseInfo.php +++ /dev/null @@ -1,61 +0,0 @@ -. - */ - -require_once 'creole/metadata/DatabaseInfo.php'; - -/** - * MySQLi implementation of DatabaseInfo. - * - * @author Sebastian Bergmann - * @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."); - } -} diff --git a/creole/drivers/mysqli/metadata/MySQLiTableInfo.php b/creole/drivers/mysqli/metadata/MySQLiTableInfo.php deleted file mode 100644 index 7544e49..0000000 --- a/creole/drivers/mysqli/metadata/MySQLiTableInfo.php +++ /dev/null @@ -1,143 +0,0 @@ -. - */ - -require_once 'creole/metadata/TableInfo.php'; - -/** - * MySQLi implementation of TableInfo. - * - * @author Sebastian Bergmann - * @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; - } -} diff --git a/creole/drivers/odbc/ODBCCachedResultSet.php b/creole/drivers/odbc/ODBCCachedResultSet.php deleted file mode 100644 index 0379a5b..0000000 --- a/creole/drivers/odbc/ODBCCachedResultSet.php +++ /dev/null @@ -1,218 +0,0 @@ -. - */ - -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 - * @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); - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/ODBCConnection.php b/creole/drivers/odbc/ODBCConnection.php deleted file mode 100644 index 9ae2f02..0000000 --- a/creole/drivers/odbc/ODBCConnection.php +++ /dev/null @@ -1,362 +0,0 @@ -. - */ - -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 - * @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; - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/ODBCIdGenerator.php b/creole/drivers/odbc/ODBCIdGenerator.php deleted file mode 100644 index 9720a39..0000000 --- a/creole/drivers/odbc/ODBCIdGenerator.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @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; - } - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/ODBCPreparedStatement.php b/creole/drivers/odbc/ODBCPreparedStatement.php deleted file mode 100644 index dfcb617..0000000 --- a/creole/drivers/odbc/ODBCPreparedStatement.php +++ /dev/null @@ -1,246 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; -require_once 'creole/util/Lob.php'; - -/** - * ODBC specific PreparedStatement functions. - * - * @author Dave Lawson - * @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) . "'"; - } - -} diff --git a/creole/drivers/odbc/ODBCResultSet.php b/creole/drivers/odbc/ODBCResultSet.php deleted file mode 100644 index 87024e8..0000000 --- a/creole/drivers/odbc/ODBCResultSet.php +++ /dev/null @@ -1,209 +0,0 @@ -. - */ - -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 - * @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; - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/ODBCResultSetCommon.php b/creole/drivers/odbc/ODBCResultSetCommon.php deleted file mode 100644 index 941389b..0000000 --- a/creole/drivers/odbc/ODBCResultSetCommon.php +++ /dev/null @@ -1,188 +0,0 @@ -. - */ - -require_once 'creole/ResultSet.php'; -require_once 'creole/common/ResultSetCommon.php'; - -/** - * Base class for ODBC implementation of ResultSet. - * - * @author Dave Lawson - * @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; - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/ODBCStatement.php b/creole/drivers/odbc/ODBCStatement.php deleted file mode 100644 index cfb1e28..0000000 --- a/creole/drivers/odbc/ODBCStatement.php +++ /dev/null @@ -1,64 +0,0 @@ -. - */ - -require_once 'creole/Statement.php'; -require_once 'creole/common/StatementCommon.php'; - -/** - * ODBC Statement - * - * @author Dave Lawson - * @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; - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/ODBCTypes.php b/creole/drivers/odbc/ODBCTypes.php deleted file mode 100644 index a3389c9..0000000 --- a/creole/drivers/odbc/ODBCTypes.php +++ /dev/null @@ -1,189 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; - -/** - * ODBC types / type map. - * - * @author Dave Lawson - * @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]; - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/README b/creole/drivers/odbc/README deleted file mode 100644 index 52eb533..0000000 --- a/creole/drivers/odbc/README +++ /dev/null @@ -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). - diff --git a/creole/drivers/odbc/adapters/CodeBaseAdapter.php b/creole/drivers/odbc/adapters/CodeBaseAdapter.php deleted file mode 100644 index 0bc62c1..0000000 --- a/creole/drivers/odbc/adapters/CodeBaseAdapter.php +++ /dev/null @@ -1,73 +0,0 @@ -. - */ - -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 - * @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); - } - -} - -?> \ No newline at end of file diff --git a/creole/drivers/odbc/adapters/MySQLAdapter.php b/creole/drivers/odbc/adapters/MySQLAdapter.php deleted file mode 100644 index de024da..0000000 --- a/creole/drivers/odbc/adapters/MySQLAdapter.php +++ /dev/null @@ -1,78 +0,0 @@ -. - */ - -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 - * @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); - } - -} - -?> \ No newline at end of file diff --git a/creole/drivers/odbc/adapters/ODBCAdapter.php b/creole/drivers/odbc/adapters/ODBCAdapter.php deleted file mode 100644 index adcf829..0000000 --- a/creole/drivers/odbc/adapters/ODBCAdapter.php +++ /dev/null @@ -1,115 +0,0 @@ -. - */ - -/** - * Default class for ODBC driver-specific behavior. - * - * @author Dave Lawson - * @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; - } -} - -?> \ No newline at end of file diff --git a/creole/drivers/odbc/metadata/ODBCDatabaseInfo.php b/creole/drivers/odbc/metadata/ODBCDatabaseInfo.php deleted file mode 100644 index d2f7b0a..0000000 --- a/creole/drivers/odbc/metadata/ODBCDatabaseInfo.php +++ /dev/null @@ -1,66 +0,0 @@ -. - */ - -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 - * @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. - } - -} \ No newline at end of file diff --git a/creole/drivers/odbc/metadata/ODBCTableInfo.php b/creole/drivers/odbc/metadata/ODBCTableInfo.php deleted file mode 100644 index cb8b24d..0000000 --- a/creole/drivers/odbc/metadata/ODBCTableInfo.php +++ /dev/null @@ -1,141 +0,0 @@ -. - */ - -require_once 'creole/metadata/TableInfo.php'; - -/** - * ODBC implementation of TableInfo. - * - * @author Dave Lawson - * @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; - } - -} \ No newline at end of file diff --git a/creole/drivers/oracle/OCI8Connection.php b/creole/drivers/oracle/OCI8Connection.php deleted file mode 100644 index df8a20f..0000000 --- a/creole/drivers/oracle/OCI8Connection.php +++ /dev/null @@ -1,393 +0,0 @@ -. - */ - -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 - * @author Hans Lellelid - * @author Stig Bakken - * @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: - *
-    * SELECT B.* FROM ( 
-    *          SELECT A.*, rownum as TORQUE$ROWNUM FROM ( 
-    *                  query
-    *           ) A
-    *      ) B WHERE B.TORQUE$ROWNUM > offset AND B.TORQUE$ROWNUM
-    *     <= offset + limit
-    * 
- * - * @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 ); - } -} diff --git a/creole/drivers/oracle/OCI8IdGenerator.php b/creole/drivers/oracle/OCI8IdGenerator.php deleted file mode 100644 index 14d9dce..0000000 --- a/creole/drivers/oracle/OCI8IdGenerator.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @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); - } - -} - diff --git a/creole/drivers/oracle/OCI8PreparedStatement.php b/creole/drivers/oracle/OCI8PreparedStatement.php deleted file mode 100644 index 34b4e56..0000000 --- a/creole/drivers/oracle/OCI8PreparedStatement.php +++ /dev/null @@ -1,424 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; - -/** - * Oracle (OCI8) implementation of PreparedStatement. - * - * @author David Giffin - * @author Hans Lellelid - * @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] = ''; - } - - -} - diff --git a/creole/drivers/oracle/OCI8ResultSet.php b/creole/drivers/oracle/OCI8ResultSet.php deleted file mode 100644 index 6763826..0000000 --- a/creole/drivers/oracle/OCI8ResultSet.php +++ /dev/null @@ -1,131 +0,0 @@ -. - */ - -require_once 'creole/ResultSet.php'; -require_once 'creole/common/ResultSetCommon.php'; - -/** - * Oracle (OCI8) implementation of ResultSet class. - * - * @author David Giffin - * @author Hans Lellelid - * @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 ); - } -} diff --git a/creole/drivers/oracle/OCI8Statement.php b/creole/drivers/oracle/OCI8Statement.php deleted file mode 100644 index 770b258..0000000 --- a/creole/drivers/oracle/OCI8Statement.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -require_once 'creole/Statement.php'; -require_once 'creole/common/StatementCommon.php'; - -/** - * Oracle (OCI8) Statement implementation. - * - * @author Hans Lellelid - * @version $Revision: 1.2 $ - * @package creole.drivers.oracle - */ -class OCI8Statement extends StatementCommon implements Statement { - -} diff --git a/creole/drivers/oracle/OCI8Types.php b/creole/drivers/oracle/OCI8Types.php deleted file mode 100644 index 0385dbc..0000000 --- a/creole/drivers/oracle/OCI8Types.php +++ /dev/null @@ -1,88 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; - -/** - * Oracle types / type map. - * - * @author David Giffin - * @author Hans Lellelid - * @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]; - } - -} diff --git a/creole/drivers/oracle/metadata/OCI8DatabaseInfo.php b/creole/drivers/oracle/metadata/OCI8DatabaseInfo.php deleted file mode 100644 index 28e2ac5..0000000 --- a/creole/drivers/oracle/metadata/OCI8DatabaseInfo.php +++ /dev/null @@ -1,90 +0,0 @@ -. - */ - -require_once 'creole/metadata/DatabaseInfo.php'; - -/** - * Oracle (OCI8) implementation of DatabaseInfo. - * - * @author Hans Lellelid - * @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."); - } - -} diff --git a/creole/drivers/oracle/metadata/OCI8TableInfo.php b/creole/drivers/oracle/metadata/OCI8TableInfo.php deleted file mode 100644 index b4cfd7e..0000000 --- a/creole/drivers/oracle/metadata/OCI8TableInfo.php +++ /dev/null @@ -1,273 +0,0 @@ -. - */ - -require_once 'creole/metadata/TableInfo.php'; - -/** - * Oracle (OCI8) implementation of TableInfo. - * - * @author David Giffin - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/drivers/pgsql/PgSQLConnection.php b/creole/drivers/pgsql/PgSQLConnection.php deleted file mode 100644 index a609529..0000000 --- a/creole/drivers/pgsql/PgSQLConnection.php +++ /dev/null @@ -1,260 +0,0 @@ -. - */ - -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 (Creole) - * @author Stig Bakken (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); - } - -} diff --git a/creole/drivers/pgsql/PgSQLIdGenerator.php b/creole/drivers/pgsql/PgSQLIdGenerator.php deleted file mode 100644 index bf09965..0000000 --- a/creole/drivers/pgsql/PgSQLIdGenerator.php +++ /dev/null @@ -1,84 +0,0 @@ -. - */ - -require_once 'creole/IdGenerator.php'; - -/** - * PostgreSQL IdGenerator implemenation. - * - * @author Hans Lellelid - * @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); - } - -} - diff --git a/creole/drivers/pgsql/PgSQLPreparedStatement.php b/creole/drivers/pgsql/PgSQLPreparedStatement.php deleted file mode 100644 index 2db9adc..0000000 --- a/creole/drivers/pgsql/PgSQLPreparedStatement.php +++ /dev/null @@ -1,157 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; - -/** - * PgSQL subclass for prepared statements. - * - * @author Hans Lellelid - * @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)."'"; - } - } -} diff --git a/creole/drivers/pgsql/PgSQLResultSet.php b/creole/drivers/pgsql/PgSQLResultSet.php deleted file mode 100644 index 80ecda8..0000000 --- a/creole/drivers/pgsql/PgSQLResultSet.php +++ /dev/null @@ -1,213 +0,0 @@ -. - */ - -require_once 'creole/ResultSet.php'; -require_once 'creole/common/ResultSetCommon.php'; - -/** - * PostgreSQL implementation of ResultSet. - * - * @author Hans Lellelid - * @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'); - } - -} diff --git a/creole/drivers/pgsql/PgSQLResultSetIterator.php b/creole/drivers/pgsql/PgSQLResultSetIterator.php deleted file mode 100644 index ffe2853..0000000 --- a/creole/drivers/pgsql/PgSQLResultSetIterator.php +++ /dev/null @@ -1,109 +0,0 @@ -. - */ - -/** - * 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 - * @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; - } -} diff --git a/creole/drivers/pgsql/PgSQLStatement.php b/creole/drivers/pgsql/PgSQLStatement.php deleted file mode 100644 index 6fd51b0..0000000 --- a/creole/drivers/pgsql/PgSQLStatement.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -require_once 'creole/Statement.php'; -require_once 'creole/common/StatementCommon.php'; - -/** - * PostgreSQL Statement implementation. - * - * @author Hans Lellelid - * @version $Revision: 1.1 $ - * @package creole.drivers.pgsql - */ -class PgSQLStatement extends StatementCommon implements Statement { - -} diff --git a/creole/drivers/pgsql/PgSQLTypes.php b/creole/drivers/pgsql/PgSQLTypes.php deleted file mode 100644 index 8ae75d0..0000000 --- a/creole/drivers/pgsql/PgSQLTypes.php +++ /dev/null @@ -1,101 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; - -/** - * PostgreSQL types / type map. - * - * @author Hans Lellelid - * @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]; - } - -} \ No newline at end of file diff --git a/creole/drivers/pgsql/metadata/PgSQLDatabaseInfo.php b/creole/drivers/pgsql/metadata/PgSQLDatabaseInfo.php deleted file mode 100644 index 0f4c97f..0000000 --- a/creole/drivers/pgsql/metadata/PgSQLDatabaseInfo.php +++ /dev/null @@ -1,113 +0,0 @@ -. - */ - -require_once 'creole/metadata/DatabaseInfo.php'; - -/** - * MySQL implementation of DatabaseInfo. - * - * @author Hans Lellelid - * @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; - } - - } - -} - diff --git a/creole/drivers/pgsql/metadata/PgSQLTableInfo.php b/creole/drivers/pgsql/metadata/PgSQLTableInfo.php deleted file mode 100644 index 3a21d0e..0000000 --- a/creole/drivers/pgsql/metadata/PgSQLTableInfo.php +++ /dev/null @@ -1,423 +0,0 @@ -. - */ - -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 - * @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; - } - - - -} \ No newline at end of file diff --git a/creole/drivers/sqlite/SQLiteConnection.php b/creole/drivers/sqlite/SQLiteConnection.php deleted file mode 100644 index b8f735b..0000000 --- a/creole/drivers/sqlite/SQLiteConnection.php +++ /dev/null @@ -1,245 +0,0 @@ -. - */ - -require_once 'creole/Connection.php'; -require_once 'creole/common/ConnectionCommon.php'; - -/** - * SQLite implementation of Connection. - * - * @author Hans Lellelid - * @author Stig Bakken - * @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); - } - -} diff --git a/creole/drivers/sqlite/SQLiteIdGenerator.php b/creole/drivers/sqlite/SQLiteIdGenerator.php deleted file mode 100644 index 7f25fda..0000000 --- a/creole/drivers/sqlite/SQLiteIdGenerator.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @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()); - } - -} - diff --git a/creole/drivers/sqlite/SQLitePreparedStatement.php b/creole/drivers/sqlite/SQLitePreparedStatement.php deleted file mode 100644 index 396ba5b..0000000 --- a/creole/drivers/sqlite/SQLitePreparedStatement.php +++ /dev/null @@ -1,61 +0,0 @@ -. - */ - -require_once 'creole/PreparedStatement.php'; -require_once 'creole/common/PreparedStatementCommon.php'; - -/** - * MySQL subclass for prepared statements. - * - * @author Hans Lellelid - * @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 ) . "'"; - } - } - -} diff --git a/creole/drivers/sqlite/SQLiteResultSet.php b/creole/drivers/sqlite/SQLiteResultSet.php deleted file mode 100644 index 1591c81..0000000 --- a/creole/drivers/sqlite/SQLiteResultSet.php +++ /dev/null @@ -1,119 +0,0 @@ -. - */ - -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 - * @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(); - } -} diff --git a/creole/drivers/sqlite/SQLiteResultSetIterator.php b/creole/drivers/sqlite/SQLiteResultSetIterator.php deleted file mode 100644 index 340829d..0000000 --- a/creole/drivers/sqlite/SQLiteResultSetIterator.php +++ /dev/null @@ -1,88 +0,0 @@ -. - */ - -/** - * Optimized iterator for SQLite. - * - * @author Hans Lellelid - * @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++; - } - -} diff --git a/creole/drivers/sqlite/SQLiteStatement.php b/creole/drivers/sqlite/SQLiteStatement.php deleted file mode 100644 index 103f124..0000000 --- a/creole/drivers/sqlite/SQLiteStatement.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -require_once 'creole/Statement.php'; -require_once 'creole/common/StatementCommon.php'; - -/** - * SQLite Statement - * - * @author Hans Lellelid - * @version $Revision: 1.1 $ - * @package creole.drivers.sqlite - */ -class SQLiteStatement extends StatementCommon implements Statement { - -} diff --git a/creole/drivers/sqlite/SQLiteTypes.php b/creole/drivers/sqlite/SQLiteTypes.php deleted file mode 100644 index 3dab073..0000000 --- a/creole/drivers/sqlite/SQLiteTypes.php +++ /dev/null @@ -1,108 +0,0 @@ -. - */ - -require_once 'creole/CreoleTypes.php'; - -/** - * MySQL types / type map. - * - * @author Hans Lellelid - * @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]; - } - -} \ No newline at end of file diff --git a/creole/drivers/sqlite/metadata/SQLiteDatabaseInfo.php b/creole/drivers/sqlite/metadata/SQLiteDatabaseInfo.php deleted file mode 100644 index 56c724d..0000000 --- a/creole/drivers/sqlite/metadata/SQLiteDatabaseInfo.php +++ /dev/null @@ -1,64 +0,0 @@ -. - */ - -require_once 'creole/metadata/DatabaseInfo.php'; - -/** - * SQLite implementation of DatabaseInfo. - * - * @author Hans Lellelid - * @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."); - } - -} diff --git a/creole/drivers/sqlite/metadata/SQLiteTableInfo.php b/creole/drivers/sqlite/metadata/SQLiteTableInfo.php deleted file mode 100644 index 5018f82..0000000 --- a/creole/drivers/sqlite/metadata/SQLiteTableInfo.php +++ /dev/null @@ -1,135 +0,0 @@ -. - */ - -require_once 'creole/metadata/TableInfo.php'; - -/** - * MySQL implementation of TableInfo. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/metadata/ColumnInfo.php b/creole/metadata/ColumnInfo.php deleted file mode 100644 index 4f5cb43..0000000 --- a/creole/metadata/ColumnInfo.php +++ /dev/null @@ -1,232 +0,0 @@ -. - */ - -/** - * Represents a Column. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/metadata/DatabaseInfo.php b/creole/metadata/DatabaseInfo.php deleted file mode 100644 index 27d3e97..0000000 --- a/creole/metadata/DatabaseInfo.php +++ /dev/null @@ -1,206 +0,0 @@ -. - */ - -/** - * "Info" metadata class for a database. - * - * @author Hans Lellelid - * @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; - } -} - diff --git a/creole/metadata/ForeignKeyInfo.php b/creole/metadata/ForeignKeyInfo.php deleted file mode 100644 index 89d8630..0000000 --- a/creole/metadata/ForeignKeyInfo.php +++ /dev/null @@ -1,103 +0,0 @@ -. - */ - -/** - * Represents a foreign key. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/metadata/IndexInfo.php b/creole/metadata/IndexInfo.php deleted file mode 100644 index de88fa2..0000000 --- a/creole/metadata/IndexInfo.php +++ /dev/null @@ -1,84 +0,0 @@ -. - */ - -/** - * Represents an index. - * - * @author Hans Lellelid - * @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; - } - -} diff --git a/creole/metadata/PrimaryKeyInfo.php b/creole/metadata/PrimaryKeyInfo.php deleted file mode 100644 index 56ec9ea..0000000 --- a/creole/metadata/PrimaryKeyInfo.php +++ /dev/null @@ -1,91 +0,0 @@ -. - */ - -/** - * Represents a PrimaryKey - * - * @author Hans Lellelid - * @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; - } -} diff --git a/creole/metadata/TableInfo.php b/creole/metadata/TableInfo.php deleted file mode 100644 index 763e0d6..0000000 --- a/creole/metadata/TableInfo.php +++ /dev/null @@ -1,305 +0,0 @@ -. - */ - -/** - * Represents a table. - * - * @author Hans Lellelid - * @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; - } -} diff --git a/creole/util/Blob.php b/creole/util/Blob.php deleted file mode 100644 index b611fe6..0000000 --- a/creole/util/Blob.php +++ /dev/null @@ -1,62 +0,0 @@ -. - */ - -require_once 'creole/util/Lob.php'; - -/** - * A class for handling binary LOBs. - * - * @author Hans Lellelid - * @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; - } - - } - - - -} \ No newline at end of file diff --git a/creole/util/Clob.php b/creole/util/Clob.php deleted file mode 100644 index 051b102..0000000 --- a/creole/util/Clob.php +++ /dev/null @@ -1,112 +0,0 @@ -. - */ - -require_once 'creole/util/Lob.php'; - -/** - * A class for handling character (ASCII) LOBs. - * - * @author Hans Lellelid - * @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; - } - - } - - - -} \ No newline at end of file diff --git a/creole/util/Lob.php b/creole/util/Lob.php deleted file mode 100644 index dd73186..0000000 --- a/creole/util/Lob.php +++ /dev/null @@ -1,243 +0,0 @@ -. - */ - -/** - * An abstract class for handling LOB (Locator Object) columns. - * - * @author Hans Lellelid - * @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; - } -} diff --git a/creole/util/sql/SQLStatementExtractor.php b/creole/util/sql/SQLStatementExtractor.php deleted file mode 100644 index f4c79a4..0000000 --- a/creole/util/sql/SQLStatementExtractor.php +++ /dev/null @@ -1,164 +0,0 @@ -. - */ - -/** - * Static class for extracting SQL statements from a string or file. - * - * @author Hans Lellelid - * @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 $len-1 || $endpos < $startpos) { - trigger_error("substring(), Endindex out of bounds must be $startpos'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; -} - -?> diff --git a/h2o/context.php b/h2o/context.php deleted file mode 100644 index b0489b4..0000000 --- a/h2o/context.php +++ /dev/null @@ -1,264 +0,0 @@ - 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}]"; - } -} -?> \ No newline at end of file diff --git a/h2o/datatype.php b/h2o/datatype.php deleted file mode 100644 index 95d395b..0000000 --- a/h2o/datatype.php +++ /dev/null @@ -1,176 +0,0 @@ -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); -} -?> diff --git a/h2o/errors.php b/h2o/errors.php deleted file mode 100644 index 5044134..0000000 --- a/h2o/errors.php +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/h2o/filters.php b/h2o/filters.php deleted file mode 100644 index 98d1f0c..0000000 --- a/h2o/filters.php +++ /dev/null @@ -1,345 +0,0 @@ - $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 = "". ($truncate ? truncate($url,$truncate): $url).''; - 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('�','.',','), 'GBP' => '�', 'JPY' => '�', - '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('', $url, $attr); - } - - static function css_tag($url, $options = array()) { - $attr = self::htmlAttribute(array('media'), $options); - return sprintf('', $url, $attr); - } - - static function script_tag($url, $options = array()) { - return sprintf('', $url); - } - - static function links_to($text, $url, $options = array()) { - $attrs = self::htmlAttribute(array('ref'), $options); - $url = self::base_url($url, $options); - return sprintf('%s', $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", "
\n", $value); - } - - static function nl2pbr($value) { - $result = array(); - $parts = preg_split('/(\r?\n){2,}/m', $value); - foreach ($parts as $part) { - array_push($result, '

' . HtmlFilters::nl2br($part) . '

'); - } - 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')); - -?> diff --git a/h2o/loaders.php b/h2o/loaders.php deleted file mode 100644 index dd33d5c..0000000 --- a/h2o/loaders.php +++ /dev/null @@ -1,229 +0,0 @@ -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() {} -} - -?> diff --git a/h2o/nodes.php b/h2o/nodes.php deleted file mode 100644 index 6273c1b..0000000 --- a/h2o/nodes.php +++ /dev/null @@ -1,88 +0,0 @@ -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)); - } -} - - -?> \ No newline at end of file diff --git a/h2o/parser.php b/h2o/parser.php deleted file mode 100644 index c6ff81d..0000000 --- a/h2o/parser.php +++ /dev/null @@ -1,291 +0,0 @@ -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; - } -} -?> diff --git a/h2o/tags.php b/h2o/tags.php deleted file mode 100644 index e53937f..0000000 --- a/h2o/tags.php +++ /dev/null @@ -1,436 +0,0 @@ -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 = "
". print_r($object, true). "
"; - $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("
"); - } -} - -H2o::addTag(array('block', 'extends', 'include', 'if', 'ifchanged', 'for', 'with', 'cycle', 'load', 'debug', 'now', 'autoescape', 'csrf_token')); -?> \ No newline at end of file