2013-04-13 06:17:56 +00:00
|
|
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
2011-07-20 12:57:07 +00:00
|
|
|
/**
|
|
|
|
* PDO database connection.
|
|
|
|
*
|
|
|
|
* @package Kohana/Database
|
|
|
|
* @category Drivers
|
|
|
|
* @author Kohana Team
|
|
|
|
* @copyright (c) 2008-2009 Kohana Team
|
|
|
|
* @license http://kohanaphp.com/license
|
|
|
|
*/
|
|
|
|
class Kohana_Database_PDO extends Database {
|
|
|
|
|
|
|
|
// PDO uses no quoting for identifiers
|
|
|
|
protected $_identifier = '';
|
|
|
|
|
2013-04-13 06:17:56 +00:00
|
|
|
public function __construct($name, array $config)
|
2011-07-20 12:57:07 +00:00
|
|
|
{
|
|
|
|
parent::__construct($name, $config);
|
|
|
|
|
|
|
|
if (isset($this->_config['identifier']))
|
|
|
|
{
|
|
|
|
// Allow the identifier to be overloaded per-connection
|
|
|
|
$this->_identifier = (string) $this->_config['identifier'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function connect()
|
|
|
|
{
|
|
|
|
if ($this->_connection)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Extract the connection parameters, adding required variabels
|
|
|
|
extract($this->_config['connection'] + array(
|
|
|
|
'dsn' => '',
|
|
|
|
'username' => NULL,
|
|
|
|
'password' => NULL,
|
|
|
|
'persistent' => FALSE,
|
|
|
|
));
|
|
|
|
|
|
|
|
// Clear the connection parameters for security
|
|
|
|
unset($this->_config['connection']);
|
|
|
|
|
|
|
|
// Force PDO to use exceptions for all errors
|
2013-04-13 06:17:56 +00:00
|
|
|
$options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
|
2011-07-20 12:57:07 +00:00
|
|
|
|
|
|
|
if ( ! empty($persistent))
|
|
|
|
{
|
|
|
|
// Make the connection persistent
|
2013-04-13 06:17:56 +00:00
|
|
|
$options[PDO::ATTR_PERSISTENT] = TRUE;
|
2011-07-20 12:57:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Create a new PDO connection
|
2013-04-13 06:17:56 +00:00
|
|
|
$this->_connection = new PDO($dsn, $username, $password, $options);
|
2011-07-20 12:57:07 +00:00
|
|
|
}
|
|
|
|
catch (PDOException $e)
|
|
|
|
{
|
|
|
|
throw new Database_Exception(':error',
|
|
|
|
array(':error' => $e->getMessage()),
|
|
|
|
$e->getCode());
|
|
|
|
}
|
2013-04-13 06:17:56 +00:00
|
|
|
}
|
2011-07-20 12:57:07 +00:00
|
|
|
|
2013-04-13 06:17:56 +00:00
|
|
|
/**
|
|
|
|
* Create or redefine a SQL aggregate function.
|
|
|
|
*
|
|
|
|
* [!!] Works only with SQLite
|
|
|
|
*
|
|
|
|
* @link http://php.net/manual/function.pdo-sqlitecreateaggregate
|
|
|
|
*
|
|
|
|
* @param string $name Name of the SQL function to be created or redefined
|
|
|
|
* @param callback $step Called for each row of a result set
|
|
|
|
* @param callback $final Called after all rows of a result set have been processed
|
|
|
|
* @param integer $arguments Number of arguments that the SQL function takes
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function create_aggregate($name, $step, $final, $arguments = -1)
|
|
|
|
{
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
|
|
|
return $this->_connection->sqliteCreateAggregate(
|
|
|
|
$name, $step, $final, $arguments
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create or redefine a SQL function.
|
|
|
|
*
|
|
|
|
* [!!] Works only with SQLite
|
|
|
|
*
|
|
|
|
* @link http://php.net/manual/function.pdo-sqlitecreatefunction
|
|
|
|
*
|
|
|
|
* @param string $name Name of the SQL function to be created or redefined
|
|
|
|
* @param callback $callback Callback which implements the SQL function
|
|
|
|
* @param integer $arguments Number of arguments that the SQL function takes
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function create_function($name, $callback, $arguments = -1)
|
|
|
|
{
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
|
|
|
return $this->_connection->sqliteCreateFunction(
|
|
|
|
$name, $callback, $arguments
|
|
|
|
);
|
2011-07-20 12:57:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function disconnect()
|
|
|
|
{
|
|
|
|
// Destroy the PDO object
|
|
|
|
$this->_connection = NULL;
|
|
|
|
|
|
|
|
return parent::disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function set_charset($charset)
|
|
|
|
{
|
|
|
|
// Make sure the database is connected
|
2013-04-13 06:17:56 +00:00
|
|
|
$this->_connection OR $this->connect();
|
2011-07-20 12:57:07 +00:00
|
|
|
|
2013-04-13 06:17:56 +00:00
|
|
|
// This SQL-92 syntax is not supported by all drivers
|
2011-07-20 12:57:07 +00:00
|
|
|
$this->_connection->exec('SET NAMES '.$this->quote($charset));
|
|
|
|
}
|
|
|
|
|
|
|
|
public function query($type, $sql, $as_object = FALSE, array $params = NULL)
|
|
|
|
{
|
|
|
|
// Make sure the database is connected
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
2013-04-13 06:17:56 +00:00
|
|
|
if (Kohana::$profiling)
|
2011-07-20 12:57:07 +00:00
|
|
|
{
|
|
|
|
// Benchmark this query for the current instance
|
|
|
|
$benchmark = Profiler::start("Database ({$this->_instance})", $sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
$result = $this->_connection->query($sql);
|
|
|
|
}
|
|
|
|
catch (Exception $e)
|
|
|
|
{
|
|
|
|
if (isset($benchmark))
|
|
|
|
{
|
|
|
|
// This benchmark is worthless
|
|
|
|
Profiler::delete($benchmark);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the exception in a database exception
|
|
|
|
throw new Database_Exception(':error [ :query ]',
|
|
|
|
array(
|
|
|
|
':error' => $e->getMessage(),
|
|
|
|
':query' => $sql
|
|
|
|
),
|
|
|
|
$e->getCode());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($benchmark))
|
|
|
|
{
|
|
|
|
Profiler::stop($benchmark);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the last query
|
|
|
|
$this->last_query = $sql;
|
|
|
|
|
|
|
|
if ($type === Database::SELECT)
|
|
|
|
{
|
|
|
|
// Convert the result into an array, as PDOStatement::rowCount is not reliable
|
|
|
|
if ($as_object === FALSE)
|
|
|
|
{
|
|
|
|
$result->setFetchMode(PDO::FETCH_ASSOC);
|
|
|
|
}
|
|
|
|
elseif (is_string($as_object))
|
|
|
|
{
|
|
|
|
$result->setFetchMode(PDO::FETCH_CLASS, $as_object, $params);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$result->setFetchMode(PDO::FETCH_CLASS, 'stdClass');
|
|
|
|
}
|
|
|
|
|
|
|
|
$result = $result->fetchAll();
|
|
|
|
|
|
|
|
// Return an iterator of results
|
|
|
|
return new Database_Result_Cached($result, $sql, $as_object, $params);
|
|
|
|
}
|
|
|
|
elseif ($type === Database::INSERT)
|
|
|
|
{
|
|
|
|
// Return a list of insert id and rows created
|
|
|
|
return array(
|
|
|
|
$this->_connection->lastInsertId(),
|
|
|
|
$result->rowCount(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Return the number of rows affected
|
|
|
|
return $result->rowCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function begin($mode = NULL)
|
|
|
|
{
|
|
|
|
// Make sure the database is connected
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
|
|
|
return $this->_connection->beginTransaction();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function commit()
|
|
|
|
{
|
|
|
|
// Make sure the database is connected
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
|
|
|
return $this->_connection->commit();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function rollback()
|
|
|
|
{
|
|
|
|
// Make sure the database is connected
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
|
|
|
return $this->_connection->rollBack();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function list_tables($like = NULL)
|
|
|
|
{
|
|
|
|
throw new Kohana_Exception('Database method :method is not supported by :class',
|
|
|
|
array(':method' => __FUNCTION__, ':class' => __CLASS__));
|
|
|
|
}
|
|
|
|
|
|
|
|
public function list_columns($table, $like = NULL, $add_prefix = TRUE)
|
|
|
|
{
|
|
|
|
throw new Kohana_Exception('Database method :method is not supported by :class',
|
|
|
|
array(':method' => __FUNCTION__, ':class' => __CLASS__));
|
|
|
|
}
|
|
|
|
|
|
|
|
public function escape($value)
|
|
|
|
{
|
|
|
|
// Make sure the database is connected
|
|
|
|
$this->_connection or $this->connect();
|
|
|
|
|
|
|
|
return $this->_connection->quote($value);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End Database_PDO
|