Add interface for pdo drivers to enforce the same interface on the Firebird driver

This commit is contained in:
Timothy Warren 2014-03-26 20:49:33 -04:00
parent 56c061a7d1
commit 846e68acc4
9 changed files with 326 additions and 128 deletions

View File

@ -21,7 +21,7 @@
* @package Query * @package Query
* @subpackage Query * @subpackage Query
*/ */
abstract class DB_PDO extends PDO { abstract class Abstract_Driver extends PDO implements idriver {
// Reference to the last executed query // Reference to the last executed query
protected $statement; protected $statement;
@ -49,7 +49,7 @@ abstract class DB_PDO extends PDO {
* @param string $password * @param string $password
* @param array $driver_options * @param array $driver_options
*/ */
public function __construct($dsn, $username=NULL, $password=NULL, $driver_options=array()) public function __construct($dsn, $username=NULL, $password=NULL, array $driver_options=array())
{ {
// Set PDO to display errors as exceptions // Set PDO to display errors as exceptions
$driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;

132
classes/idriver.php Normal file
View File

@ -0,0 +1,132 @@
<?php
/**
* Query
*
* Free Query Builder / Database Abstraction Layer
*
* @package Query
* @author Timothy J. Warren
* @copyright Copyright (c) 2012 - 2014
* @link https://github.com/aviat4ion/Query
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* PDO Interface to implement for database drivers
*/
interface idriver {
/**
* Constructor/Connection method
*
* @param string $dsn
* @param [string] $username
* @param [string] $password
* @param [array] $driver_options
* @return void
*/
public function __construct($dsn, $username=NULL, $password=NULL, array $driver_options = array());
/**
* Begin a transaction
*
* @return bool
*/
public function beginTransaction();
/**
* Commit a transaction
*
* @return bool
*/
public function commit();
/**
* Return the current error code
*
* @return mixed
*/
public function errorCode();
/**
* Return information about the current error
*
* @return array
*/
public function errorInfo();
/**
* Execute an SQL statement and return the number of affected rows
*
* @param string $statement
* @return int
*/
public function exec($statement);
/**
* Get a connection attribute for the current db driver
*
* @param int $attribute
* @returm mixed
*/
public function getAttribute($attribute);
/**
* Check if currently in a transaction
*
* @return bool
*/
public function inTransaction();
/**
* Returns the id of the last row inserted into the database
*
* @param [string] $name
* @return string
*/
public function lastInsertId($name = NULL);
/**
* Prepare a statement for execution
*
* @param string $statement
* @param [array] $driver_options
* @return PDOStatement
*/
public function prepare($statement, $driver_options = array());
/**
* Executes an sql statement
*
* @param string $statement
* @return PDOStatement
*/
public function query();
/**
* Quotes a string for use in a query
*
* @param string $string
* @param [int] $parameter_type
* #return string
*/
public function quote($string, $parameter_type = PDO::PARAM_STRING);
/**
* Rollback a transaction
*
* @return bool
*/
public function rollback();
/**
* Set a connection attribute
* @param int $attribute
* @param mixed $value
* @return bool
*/
public function setAttribute($attribute, $value);
}
// End of idriver.php

View File

@ -27,7 +27,7 @@ class Query_Builder implements iQuery_Builder {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Compiled 'select' clause // Compiled 'select' clause
protected $select_string; protected $select_string = '';
// Compiled 'from' clause // Compiled 'from' clause
protected $from_string; protected $from_string;
@ -46,13 +46,13 @@ class Query_Builder implements iQuery_Builder {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Keys for insert/update statement // Keys for insert/update statement
protected $set_array_keys; protected $set_array_keys = array();
// Key/val pairs for order by clause // Key/val pairs for order by clause
protected $order_array; protected $order_array = array();
// Key/val pairs for group by clause // Key/val pairs for group by clause
protected $group_array; protected $group_array = array();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! Other Class vars // ! Other Class vars
@ -94,7 +94,7 @@ class Query_Builder implements iQuery_Builder {
public $queries; public $queries;
// Whether to do only an explain on the query // Whether to do only an explain on the query
protected $explain = FALSE; protected $explain;
// Subclass instances // Subclass instances
public $db; public $db;
@ -969,15 +969,7 @@ class Query_Builder implements iQuery_Builder {
$this->limit($limit, $offset); $this->limit($limit, $offset);
} }
// Do prepared statements for anything involving a "where" clause return $this->_run("get", $table);
if ( ! empty($this->query_map) || ! empty($this->having_map))
{
return $this->_run("get", $table);
}
else
{
return $this->_run("get", $table, TRUE);
}
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -1032,16 +1024,8 @@ class Query_Builder implements iQuery_Builder {
$this->from($table); $this->from($table);
} }
// Do prepared statements for anything involving a "where" clause $result = $this->_run('get', $table);
if ( ! empty($this->query_map))
{
$result = $this->_run('get', $table);
}
else
{
// Otherwise, a simple query will do.
$result = $this->_run('get', $table, TRUE);
}
$rows = $result->fetchAll(); $rows = $result->fetchAll();
@ -1084,7 +1068,7 @@ class Query_Builder implements iQuery_Builder {
if ( ! is_null($sql)) if ( ! is_null($sql))
{ {
return $this->_run('', $table, FALSE, $sql, $data); return $this->_run('', $table, $sql, $data);
} }
return NULL; return NULL;
@ -1228,23 +1212,37 @@ class Query_Builder implements iQuery_Builder {
*/ */
public function reset_query() public function reset_query()
{ {
foreach($this as $name => $var) $null_properties = array(
'select_string',
'from_string',
'set_string',
'order_string',
'group_string',
'limit',
'offset',
'explain'
);
$array_properties = array(
'set_array_keys',
'order_array',
'group_array',
'values',
'where_values',
'query_map',
'having_map'
);
// Reset strings and booleans
foreach($null_properties as $var)
{ {
$skip = array('db','sql','queries','table_prefix','parser','conn_name'); $this->$var = NULL;
}
// Skip properties that are needed for every query // Reset arrays
if (in_array($name, $skip)) continue; foreach($array_properties as $var)
{
// Nothing query-generation related is safe! $this->$var = array();
$this->$name = NULL;
// Set empty arrays
$this->values = array();
$this->query_map = array();
// Set select string as an empty string, for proper handling
// of the 'distinct' keyword
$this->select_string = '';
} }
} }
@ -1255,12 +1253,11 @@ class Query_Builder implements iQuery_Builder {
* *
* @param string $type * @param string $type
* @param string $table * @param string $table
* @param bool $simple
* @param string $sql * @param string $sql
* @param mixed $vals * @param mixed $vals
* @return mixed * @return mixed
*/ */
protected function _run($type, $table, $simple=FALSE, $sql=NULL, $vals=NULL) protected function _run($type, $table, $sql=NULL, $vals=NULL)
{ {
if (is_null($sql)) if (is_null($sql))
{ {
@ -1276,7 +1273,7 @@ class Query_Builder implements iQuery_Builder {
$start_time = microtime(TRUE); $start_time = microtime(TRUE);
if ($simple) if (empty($vals))
{ {
$res = $this->db->query($sql); $res = $this->db->query($sql);
} }
@ -1347,37 +1344,32 @@ class Query_Builder implements iQuery_Builder {
*/ */
protected function _compile_type($type='', $table='') protected function _compile_type($type='', $table='')
{ {
$table = $this->db->quote_table($table); if ($type === 'insert')
switch($type)
{ {
default: $param_count = count($this->set_array_keys);
case "get": $params = array_fill(0, $param_count, '?');
$sql = "SELECT * \nFROM {$this->from_string}"; $sql = "INSERT INTO {$table} ("
. implode(',', $this->set_array_keys)
. ")\nVALUES (".implode(',', $params).')';
}
elseif ($type === 'update')
{
$sql = "UPDATE {$table}\nSET {$this->set_string}";
}
elseif ($type === 'delete')
{
$sql = "DELETE FROM {$table}";
}
else // GET queries
{
$sql = "SELECT * \nFROM {$this->from_string}";
// Set the select string // Set the select string
if ( ! empty($this->select_string)) if ( ! empty($this->select_string))
{ {
// Replace the star with the selected fields // Replace the star with the selected fields
$sql = str_replace('*', $this->select_string, $sql); $sql = str_replace('*', $this->select_string, $sql);
} }
break;
case "insert":
$param_count = count($this->set_array_keys);
$params = array_fill(0, $param_count, '?');
$sql = "INSERT INTO {$table} ("
. implode(',', $this->set_array_keys) .
")\nVALUES (".implode(',', $params).')';
break;
case "update":
$sql = "UPDATE {$table}\nSET {$this->set_string}";
break;
case "delete":
$sql = "DELETE FROM {$table}";
break;
} }
return $sql; return $sql;
@ -1395,7 +1387,7 @@ class Query_Builder implements iQuery_Builder {
protected function _compile($type='', $table='') protected function _compile($type='', $table='')
{ {
// Get the base clause for the query // Get the base clause for the query
$sql = $this->_compile_type($type, $table); $sql = $this->_compile_type($type, $this->db->quote_table($table));
// Set the where clause // Set the where clause
if ( ! empty($this->query_map)) if ( ! empty($this->query_map))

View File

@ -21,7 +21,7 @@
* @package Query * @package Query
* @subpackage Drivers * @subpackage Drivers
*/ */
class Firebird extends DB_PDO { class Firebird extends Abstract_Driver {
/** /**
* Reference to the last query executed * Reference to the last query executed
@ -29,22 +29,22 @@ class Firebird extends DB_PDO {
* @var object * @var object
*/ */
protected $statement = NULL; protected $statement = NULL;
/** /**
* Reference to the resource returned by * Reference to the resource returned by
* the last query executed * the last query executed
* *
* @var resource * @var resource
*/ */
protected $statement_link; protected $statement_link = NULL;
/** /**
* Reference to the current transaction * Reference to the current transaction
* *
* @var resource * @var resource
*/ */
protected $trans; protected $trans = NULL;
/** /**
* Reference to the connection resource * Reference to the connection resource
* *
@ -60,29 +60,29 @@ class Firebird extends DB_PDO {
* @param string $pass * @param string $pass
* @param array $options * @param array $options
*/ */
public function __construct($dbpath, $user='SYSDBA', $pass='masterkey', $options = array()) public function __construct($dbpath, $user='SYSDBA', $pass='masterkey', array $options = array())
{ {
if (isset($options[PDO::ATTR_PERSISTENT]) && $options[PDO::ATTR_PERSISTENT] == TRUE) if (isset($options[PDO::ATTR_PERSISTENT]) && $options[PDO::ATTR_PERSISTENT] == TRUE)
{ {
$this->conn = fbird_pconnect($dbpath, $user, $pass, 'utf-8', 0); $this->conn = fbird_pconnect($dbpath, $user, $pass, 'utf-8', 0);
} }
else else
{ {
$this->conn = fbird_connect($dbpath, $user, $pass, 'utf-8', 0); $this->conn = fbird_connect($dbpath, $user, $pass, 'utf-8', 0);
} }
// Throw an exception to make this match other pdo classes // Throw an exception to make this match other pdo classes
if ( ! is_resource($this->conn)) throw new PDOException(fbird_errmsg(), fbird_errcode(), NULL); if ( ! is_resource($this->conn)) throw new PDOException(fbird_errmsg(), fbird_errcode(), NULL);
// Load these classes here because this // Load these classes here because this
// driver does not call the constructor // driver does not call the constructor
// of DB_PDO, which defines these two // of DB_PDO, which defines these two
// class variables for the other drivers // class variables for the other drivers
// Load the sql class // Load the sql class
$class = __CLASS__."_sql"; $class = __CLASS__."_sql";
$this->sql = new $class(); $this->sql = new $class();
// Load the util class // Load the util class
$class = __CLASS__."_util"; $class = __CLASS__."_util";
$this->util = new $class($this); $this->util = new $class($this);
@ -104,6 +104,63 @@ class Firebird extends DB_PDO {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/**
* Execute an sql statement and return number of affected rows
*
* @param string $sql
* @return int
*/
public function exec($sql)
{
if (empty($sql)) throw new PDOException("Exec method requires an sql query!", 0, NULL);
$query = (isset($this->trans))
? fbird_query($this->trans, $sql)
: fbird_query($this->conn, $sql);
return fbird_affected_rows($query);
}
// --------------------------------------------------------------------------
/**
* Implement for compatibility with PDO
*
* @param int $attribute
* @return mixed
*/
public function getAttribute($attribute)
{
return NULL;
}
// --------------------------------------------------------------------------
/**
* Return whether the current statement is in a transaction
*
* @return bool
*/
public function inTransaction()
{
return ! is_null($this->trans);
}
// --------------------------------------------------------------------------
/**
* Returns the last value of the specified generator
*
* @param string $name
* @return mixed
*/
public function lastInsertId($name = NULL)
{
return fbird_gen_id($name, 0, $this->conn);
}
// --------------------------------------------------------------------------
/** /**
* Wrapper public function to better match PDO * Wrapper public function to better match PDO
* *
@ -111,10 +168,11 @@ class Firebird extends DB_PDO {
* @return Firebird_Result * @return Firebird_Result
* @throws PDOException * @throws PDOException
*/ */
public function query($sql) public function query($sql = '')
{ {
if (empty($sql)) throw new PDOException("Query method requires an sql query!", 0, NULL); if (empty($sql)) throw new PDOException("Query method requires an sql query!", 0, NULL);
$this->statement_link = (isset($this->trans)) $this->statement_link = (isset($this->trans))
? fbird_query($this->trans, $sql) ? fbird_query($this->trans, $sql)
: fbird_query($this->conn, $sql); : fbird_query($this->conn, $sql);
@ -122,7 +180,7 @@ class Firebird extends DB_PDO {
// Throw the error as a exception // Throw the error as a exception
$err_string = fbird_errmsg() . "Last query:" . $this->last_query; $err_string = fbird_errmsg() . "Last query:" . $this->last_query;
if ($this->statement_link === FALSE) throw new PDOException($err_string, fbird_errcode(), NULL); if ($this->statement_link === FALSE) throw new PDOException($err_string, fbird_errcode(), NULL);
$this->statement = new FireBird_Result($this->statement_link); $this->statement = new FireBird_Result($this->statement_link);
return $this->statement; return $this->statement;
@ -138,7 +196,7 @@ class Firebird extends DB_PDO {
* @return Firebird_Result * @return Firebird_Result
* @throws PDOException * @throws PDOException
*/ */
public function prepare($query, $options=NULL) public function prepare($query, $options=array())
{ {
$this->statement_link = fbird_prepare($this->conn, $query); $this->statement_link = fbird_prepare($this->conn, $query);
@ -171,7 +229,9 @@ class Firebird extends DB_PDO {
*/ */
public function commit() public function commit()
{ {
return fbird_commit($this->trans); $res = fbird_commit($this->trans);
$this->trans = NULL;
return $res;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -183,7 +243,22 @@ class Firebird extends DB_PDO {
*/ */
public function rollBack() public function rollBack()
{ {
return fbird_rollback($this->trans); $res = fbird_rollback($this->trans);
$this->trans = NULL;
return $res;
}
// --------------------------------------------------------------------------
/**
* Set a connection attribute
* @param int $attribute
* @param mixed $value
* @return bool
*/
public function setAttribute($attribute, $value)
{
return FALSE;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -200,7 +275,7 @@ class Firebird extends DB_PDO {
$query = $this->prepare($sql); $query = $this->prepare($sql);
// Set the statement in the class variable for easy later access // Set the statement in the class variable for easy later access
$this->statement_link =& $query; $this->statement_link =& $query;
return $query->execute($args); return $query->execute($args);
} }
@ -214,7 +289,7 @@ class Firebird extends DB_PDO {
* @param int $param_type * @param int $param_type
* @return string * @return string
*/ */
public function quote($str, $param_type = NULL) public function quote($str, $param_type = PDO::PARAM_STR)
{ {
if(is_numeric($str)) if(is_numeric($str))
{ {
@ -238,11 +313,11 @@ class Firebird extends DB_PDO {
return array(0, $code, $msg); return array(0, $code, $msg);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Method to emulate PDO->errorCode * Method to emulate PDO->errorCode
* *
* @return array * @return array
*/ */
@ -266,10 +341,10 @@ class Firebird extends DB_PDO {
// the firebird database // the firebird database
return NULL; return NULL;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Create sql for batch insert * Create sql for batch insert
* *
* @param string $table * @param string $table

View File

@ -19,7 +19,7 @@
* @package Query * @package Query
* @subpackage Drivers * @subpackage Drivers
*/ */
class MySQL extends DB_PDO { class MySQL extends Abstract_Driver {
/** /**
* Set the backtick as the MySQL escape character * Set the backtick as the MySQL escape character
@ -36,7 +36,7 @@ class MySQL extends DB_PDO {
* @param string $password * @param string $password
* @param array $options * @param array $options
*/ */
public function __construct($dsn, $username=null, $password=null, $options=array()) public function __construct($dsn, $username=null, $password=null, array $options=array())
{ {
// Set the charset to UTF-8 // Set the charset to UTF-8
if (defined('PDO::MYSQL_ATTR_INIT_COMMAND')) if (defined('PDO::MYSQL_ATTR_INIT_COMMAND'))
@ -45,9 +45,9 @@ class MySQL extends DB_PDO {
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF-8 COLLATE 'UTF-8'", PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF-8 COLLATE 'UTF-8'",
)); ));
} }
if (strpos($dsn, 'mysql') === FALSE) $dsn = 'mysql:'.$dsn; if (strpos($dsn, 'mysql') === FALSE) $dsn = 'mysql:'.$dsn;
parent::__construct($dsn, $username, $password, $options); parent::__construct($dsn, $username, $password, $options);
} }

View File

@ -19,7 +19,7 @@
* @package Query * @package Query
* @subpackage Drivers * @subpackage Drivers
*/ */
class PgSQL extends DB_PDO { class PgSQL extends Abstract_Driver {
/** /**
* Connect to a PosgreSQL database * Connect to a PosgreSQL database
@ -29,10 +29,10 @@ class PgSQL extends DB_PDO {
* @param string $password * @param string $password
* @param array $options * @param array $options
*/ */
public function __construct($dsn, $username=null, $password=null, $options=array()) public function __construct($dsn, $username=null, $password=null, array $options=array())
{ {
if (strpos($dsn, 'pgsql') === FALSE) $dsn = 'pgsql:'.$dsn; if (strpos($dsn, 'pgsql') === FALSE) $dsn = 'pgsql:'.$dsn;
parent::__construct($dsn, $username, $password, $options); parent::__construct($dsn, $username, $password, $options);
} }

View File

@ -19,7 +19,7 @@
* @package Query * @package Query
* @subpackage Drivers * @subpackage Drivers
*/ */
class SQLite extends DB_PDO { class SQLite extends Abstract_Driver {
/** /**
* Reference to the last executed sql query * Reference to the last executed sql query
@ -34,9 +34,10 @@ class SQLite extends DB_PDO {
* @param string $dsn * @param string $dsn
* @param string $user * @param string $user
* @param string $pass * @param string $pass
* @param array $driver_options
*/ */
public function __construct($dsn, $user=NULL, $pass=NULL) public function __construct($dsn, $user=NULL, $pass=NULL, array $driver_options=array())
{ {
// DSN is simply `sqlite:/path/to/db` // DSN is simply `sqlite:/path/to/db`
parent::__construct("sqlite:{$dsn}", $user, $pass); parent::__construct("sqlite:{$dsn}", $user, $pass);
} }
@ -87,10 +88,10 @@ class SQLite extends DB_PDO {
// that is of any importance. // that is of any importance.
return array('sqlite_master'); return array('sqlite_master');
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Create sql for batch insert * Create sql for batch insert
* *
* @param string $table * @param string $table

View File

@ -33,14 +33,14 @@ class SQLite_SQL implements iDB_SQL {
{ {
if ( ! is_numeric($offset)) if ( ! is_numeric($offset))
{ {
return $sql." LIMIT {$limit}"; return $sql."\nLIMIT {$limit}";
} }
return $sql." LIMIT {$offset}, {$limit}"; return $sql."\nLIMIT {$limit} OFFSET {$offset}";
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Get the query plan for the sql query * Get the query plan for the sql query
* *
@ -63,7 +63,7 @@ class SQLite_SQL implements iDB_SQL {
{ {
return ' RANDOM()'; return ' RANDOM()';
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
@ -166,9 +166,9 @@ SQL;
{ {
return NULL; return NULL;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* SQL to show list of field types * SQL to show list of field types
* *
@ -178,9 +178,9 @@ SQL;
{ {
return array('INTEGER', 'REAL', 'TEXT', 'BLOB'); return array('INTEGER', 'REAL', 'TEXT', 'BLOB');
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* SQL to show infromation about columns in a table * SQL to show infromation about columns in a table
* *

View File

@ -33,12 +33,10 @@ class FirebirdQBTest extends QBTest {
$params->alias = 'fire'; $params->alias = 'fire';
$params->type = 'firebird'; $params->type = 'firebird';
$params->file = $dbpath; $params->file = $dbpath;
$params->host = 'localhost'; $params->host = '127.0.0.1';
$params->user = 'sysdba'; $params->user = 'SYSDBA';
$params->pass = 'masterkey'; $params->pass = 'masterkey';
$params->prefix = 'create_'; $params->prefix = 'create_';
$params->options = array();
$params->options[PDO::ATTR_PERSISTENT] = TRUE;
$this->db = Query($params); $this->db = Query($params);
} }