mirror of
https://github.com/dg/dibi.git
synced 2025-08-12 09:04:24 +02:00
modified SVN properties
This commit is contained in:
@@ -1,497 +1,501 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi connection.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
class DibiConnection extends /*Nette::*/Object
|
||||
{
|
||||
/**
|
||||
* Current connection configuration.
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* IDibiDriver.
|
||||
* @var array
|
||||
*/
|
||||
private $driver;
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
* @var bool
|
||||
*/
|
||||
private $connected = FALSE;
|
||||
|
||||
/**
|
||||
* Is in transaction?
|
||||
* @var bool
|
||||
*/
|
||||
private $inTxn = FALSE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates object and (optionally) connects to a database.
|
||||
*
|
||||
* @param array|string|Nette::Collections::Hashtable connection parameters
|
||||
* @param string connection name
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct($config, $name = NULL)
|
||||
{
|
||||
// DSN string
|
||||
if (is_string($config)) {
|
||||
parse_str($config, $config);
|
||||
|
||||
} elseif ($config instanceof /*Nette::Collections::*/Hashtable) {
|
||||
$config = (array) $config;
|
||||
|
||||
} elseif (!is_array($config)) {
|
||||
throw new InvalidArgumentException('Configuration must be array, string or Nette::Collections::Hashtable.');
|
||||
}
|
||||
|
||||
if (!isset($config['driver'])) {
|
||||
$config['driver'] = dibi::$defaultDriver;
|
||||
}
|
||||
|
||||
$driver = preg_replace('#[^a-z0-9_]#', '_', $config['driver']);
|
||||
$class = "Dibi" . $driver . "Driver";
|
||||
if (!class_exists($class, FALSE)) {
|
||||
include_once __FILE__ . "/../../drivers/$driver.php";
|
||||
|
||||
if (!class_exists($class, FALSE)) {
|
||||
throw new DibiException("Unable to create instance of dibi driver class '$class'.");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['result:objects'])) {
|
||||
// normalize
|
||||
$val = $config['result:objects'];
|
||||
$config['result:objects'] = is_string($val) && !is_numeric($val) ? $val : (bool) $val;
|
||||
}
|
||||
|
||||
$config['name'] = $name;
|
||||
$this->config = $config;
|
||||
$this->driver = new $class;
|
||||
|
||||
if (empty($config['lazy'])) {
|
||||
$this->connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Automatically frees the resources allocated for this result set.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// disconnects and rolls back transaction - do not rely on auto-disconnect and rollback!
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final protected function connect()
|
||||
{
|
||||
if (!$this->connected) {
|
||||
$this->driver->connect($this->config);
|
||||
$this->connected = TRUE;
|
||||
dibi::notify($this, 'connected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects from a database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final public function disconnect()
|
||||
{
|
||||
if ($this->connected) {
|
||||
if ($this->inTxn) {
|
||||
$this->rollback();
|
||||
}
|
||||
$this->driver->disconnect();
|
||||
$this->connected = FALSE;
|
||||
dibi::notify($this, 'disconnected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns TRUE when connection was established.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
final public function isConnected()
|
||||
{
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns configuration variable. If no $key is passed, returns the entire array.
|
||||
*
|
||||
* @see self::__construct
|
||||
* @param string
|
||||
* @param mixed default value to use if key not found
|
||||
* @return mixed
|
||||
*/
|
||||
final public function getConfig($key = NULL, $default = NULL)
|
||||
{
|
||||
if ($key === NULL) {
|
||||
return $this->config;
|
||||
|
||||
} elseif (isset($this->config[$key])) {
|
||||
return $this->config[$key];
|
||||
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply configuration alias or default values.
|
||||
*
|
||||
* @param array connect configuration
|
||||
* @param string key
|
||||
* @param string alias key
|
||||
* @return void
|
||||
*/
|
||||
public static function alias(&$config, $key, $alias=NULL)
|
||||
{
|
||||
if (isset($config[$key])) return;
|
||||
|
||||
if ($alias !== NULL && isset($config[$alias])) {
|
||||
$config[$key] = $config[$alias];
|
||||
unset($config[$alias]);
|
||||
} else {
|
||||
$config[$key] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
final public function getResource()
|
||||
{
|
||||
return $this->driver->getResource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates (translates) and executes SQL query.
|
||||
*
|
||||
* @param array|mixed one or more arguments
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function query($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->connect();
|
||||
$trans = new DibiTranslator($this->driver);
|
||||
if ($trans->translate($args)) {
|
||||
return $this->nativeQuery($trans->sql);
|
||||
} else {
|
||||
throw new DibiException('SQL translate error: ' . $trans->sql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and prints SQL query.
|
||||
*
|
||||
* @param array|mixed one or more arguments
|
||||
* @return bool
|
||||
*/
|
||||
final public function test($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->connect();
|
||||
$trans = new DibiTranslator($this->driver);
|
||||
$ok = $trans->translate($args);
|
||||
dibi::dump($trans->sql);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query.
|
||||
*
|
||||
* @param string SQL statement.
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function nativeQuery($sql)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
dibi::$numOfQueries++;
|
||||
dibi::$sql = $sql;
|
||||
dibi::$elapsedTime = FALSE;
|
||||
$time = -microtime(TRUE);
|
||||
dibi::notify($this, 'beforeQuery', $sql);
|
||||
|
||||
if ($res = $this->driver->query($sql)) { // intentionally =
|
||||
$res = new DibiResult($res, $this->config);
|
||||
}
|
||||
|
||||
$time += microtime(TRUE);
|
||||
dibi::$elapsedTime = $time;
|
||||
dibi::$totalTime += $time;
|
||||
dibi::notify($this, 'afterQuery', $res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
|
||||
*
|
||||
* @return int number of rows
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = $this->driver->affectedRows();
|
||||
if (!is_int($rows) || $rows < 0) throw new DibiException('Cannot retrieve number of affected rows.');
|
||||
return $rows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||
*
|
||||
* @param string optional sequence name
|
||||
* @return int
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function insertId($sequence = NULL)
|
||||
{
|
||||
$id = $this->driver->insertId($sequence);
|
||||
if ($id < 1) throw new DibiException('Cannot retrieve last generated ID.');
|
||||
return (int) $id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->connect();
|
||||
if ($this->inTxn) {
|
||||
throw new DibiException('There is already an active transaction.');
|
||||
}
|
||||
$this->driver->begin();
|
||||
$this->inTxn = TRUE;
|
||||
dibi::notify($this, 'begin');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if (!$this->inTxn) {
|
||||
throw new DibiException('There is no active transaction.');
|
||||
}
|
||||
$this->driver->commit();
|
||||
$this->inTxn = FALSE;
|
||||
dibi::notify($this, 'commit');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if (!$this->inTxn) {
|
||||
throw new DibiException('There is no active transaction.');
|
||||
}
|
||||
$this->driver->rollback();
|
||||
$this->inTxn = FALSE;
|
||||
dibi::notify($this, 'rollback');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
*
|
||||
* @param string unescaped string
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string escaped and quoted string
|
||||
*/
|
||||
public function escape($value, $type = dibi::FIELD_TEXT)
|
||||
{
|
||||
$this->connect(); // MySQL & PDO require connection
|
||||
return $this->driver->escape($value, $type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
*
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
*/
|
||||
public function unescape($value, $type = dibi::FIELD_BINARY)
|
||||
{
|
||||
return $this->driver->unescape($value, $type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Delimites identifier (table's or column's name, etc.).
|
||||
*
|
||||
* @param string identifier
|
||||
* @return string delimited identifier
|
||||
*/
|
||||
public function delimite($value)
|
||||
{
|
||||
return $this->driver->escape($value, dibi::IDENTIFIER);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
*
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
$this->driver->applyLimit($sql, $limit, $offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Import SQL dump from file - extreme fast!
|
||||
*
|
||||
* @param string filename
|
||||
* @return int count of sql commands
|
||||
*/
|
||||
public function loadFile($file)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
@set_time_limit(0); // intentionally @
|
||||
|
||||
$handle = @fopen($file, 'r'); // intentionally @
|
||||
if (!$handle) {
|
||||
throw new FileNotFoundException("Cannot open file '$file'.");
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$sql = '';
|
||||
while (!feof($handle)) {
|
||||
$s = fgets($handle);
|
||||
$sql .= $s;
|
||||
if (substr(rtrim($s), -1) === ';') {
|
||||
$this->driver->query($sql);
|
||||
$sql = '';
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a information of the current database.
|
||||
*
|
||||
* @return DibiReflection
|
||||
*/
|
||||
public function getDibiReflection()
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prevents unserialization.
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prevents serialization.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
|
||||
}
|
||||
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi connection.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiConnection extends /*Nette::*/Object
|
||||
{
|
||||
/**
|
||||
* Current connection configuration.
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* IDibiDriver.
|
||||
* @var array
|
||||
*/
|
||||
private $driver;
|
||||
|
||||
/**
|
||||
* Is connected?
|
||||
* @var bool
|
||||
*/
|
||||
private $connected = FALSE;
|
||||
|
||||
/**
|
||||
* Is in transaction?
|
||||
* @var bool
|
||||
*/
|
||||
private $inTxn = FALSE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates object and (optionally) connects to a database.
|
||||
*
|
||||
* @param array|string|Nette::Collections::Hashtable connection parameters
|
||||
* @param string connection name
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct($config, $name = NULL)
|
||||
{
|
||||
if (class_exists(/*Nette::*/'Debug', FALSE)) {
|
||||
/*Nette::*/Debug::addColophon(array('dibi', 'getColophon'));
|
||||
}
|
||||
|
||||
// DSN string
|
||||
if (is_string($config)) {
|
||||
parse_str($config, $config);
|
||||
|
||||
} elseif ($config instanceof /*Nette::Collections::*/Hashtable) {
|
||||
$config = (array) $config;
|
||||
|
||||
} elseif (!is_array($config)) {
|
||||
throw new InvalidArgumentException('Configuration must be array, string or Nette::Collections::Hashtable.');
|
||||
}
|
||||
|
||||
if (!isset($config['driver'])) {
|
||||
$config['driver'] = dibi::$defaultDriver;
|
||||
}
|
||||
|
||||
$driver = preg_replace('#[^a-z0-9_]#', '_', $config['driver']);
|
||||
$class = "Dibi" . $driver . "Driver";
|
||||
if (!class_exists($class, FALSE)) {
|
||||
include_once __FILE__ . "/../../drivers/$driver.php";
|
||||
|
||||
if (!class_exists($class, FALSE)) {
|
||||
throw new DibiException("Unable to create instance of dibi driver class '$class'.");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['result:objects'])) {
|
||||
// normalize
|
||||
$val = $config['result:objects'];
|
||||
$config['result:objects'] = is_string($val) && !is_numeric($val) ? $val : (bool) $val;
|
||||
}
|
||||
|
||||
$config['name'] = $name;
|
||||
$this->config = $config;
|
||||
$this->driver = new $class;
|
||||
|
||||
if (empty($config['lazy'])) {
|
||||
$this->connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Automatically frees the resources allocated for this result set.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// disconnects and rolls back transaction - do not rely on auto-disconnect and rollback!
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final protected function connect()
|
||||
{
|
||||
if (!$this->connected) {
|
||||
$this->driver->connect($this->config);
|
||||
$this->connected = TRUE;
|
||||
dibi::notify($this, 'connected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects from a database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final public function disconnect()
|
||||
{
|
||||
if ($this->connected) {
|
||||
if ($this->inTxn) {
|
||||
$this->rollback();
|
||||
}
|
||||
$this->driver->disconnect();
|
||||
$this->connected = FALSE;
|
||||
dibi::notify($this, 'disconnected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns TRUE when connection was established.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
final public function isConnected()
|
||||
{
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns configuration variable. If no $key is passed, returns the entire array.
|
||||
*
|
||||
* @see self::__construct
|
||||
* @param string
|
||||
* @param mixed default value to use if key not found
|
||||
* @return mixed
|
||||
*/
|
||||
final public function getConfig($key = NULL, $default = NULL)
|
||||
{
|
||||
if ($key === NULL) {
|
||||
return $this->config;
|
||||
|
||||
} elseif (isset($this->config[$key])) {
|
||||
return $this->config[$key];
|
||||
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply configuration alias or default values.
|
||||
*
|
||||
* @param array connect configuration
|
||||
* @param string key
|
||||
* @param string alias key
|
||||
* @return void
|
||||
*/
|
||||
public static function alias(&$config, $key, $alias=NULL)
|
||||
{
|
||||
if (isset($config[$key])) return;
|
||||
|
||||
if ($alias !== NULL && isset($config[$alias])) {
|
||||
$config[$key] = $config[$alias];
|
||||
unset($config[$alias]);
|
||||
} else {
|
||||
$config[$key] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
final public function getResource()
|
||||
{
|
||||
return $this->driver->getResource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates (translates) and executes SQL query.
|
||||
*
|
||||
* @param array|mixed one or more arguments
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function query($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->connect();
|
||||
$trans = new DibiTranslator($this->driver);
|
||||
if ($trans->translate($args)) {
|
||||
return $this->nativeQuery($trans->sql);
|
||||
} else {
|
||||
throw new DibiException('SQL translate error: ' . $trans->sql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and prints SQL query.
|
||||
*
|
||||
* @param array|mixed one or more arguments
|
||||
* @return bool
|
||||
*/
|
||||
final public function test($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->connect();
|
||||
$trans = new DibiTranslator($this->driver);
|
||||
$ok = $trans->translate($args);
|
||||
dibi::dump($trans->sql);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query.
|
||||
*
|
||||
* @param string SQL statement.
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function nativeQuery($sql)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
dibi::$numOfQueries++;
|
||||
dibi::$sql = $sql;
|
||||
dibi::$elapsedTime = FALSE;
|
||||
$time = -microtime(TRUE);
|
||||
dibi::notify($this, 'beforeQuery', $sql);
|
||||
|
||||
if ($res = $this->driver->query($sql)) { // intentionally =
|
||||
$res = new DibiResult($res, $this->config);
|
||||
}
|
||||
|
||||
$time += microtime(TRUE);
|
||||
dibi::$elapsedTime = $time;
|
||||
dibi::$totalTime += $time;
|
||||
dibi::notify($this, 'afterQuery', $res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
|
||||
*
|
||||
* @return int number of rows
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = $this->driver->affectedRows();
|
||||
if (!is_int($rows) || $rows < 0) throw new DibiException('Cannot retrieve number of affected rows.');
|
||||
return $rows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||
*
|
||||
* @param string optional sequence name
|
||||
* @return int
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function insertId($sequence = NULL)
|
||||
{
|
||||
$id = $this->driver->insertId($sequence);
|
||||
if ($id < 1) throw new DibiException('Cannot retrieve last generated ID.');
|
||||
return (int) $id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->connect();
|
||||
if ($this->inTxn) {
|
||||
throw new DibiException('There is already an active transaction.');
|
||||
}
|
||||
$this->driver->begin();
|
||||
$this->inTxn = TRUE;
|
||||
dibi::notify($this, 'begin');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if (!$this->inTxn) {
|
||||
throw new DibiException('There is no active transaction.');
|
||||
}
|
||||
$this->driver->commit();
|
||||
$this->inTxn = FALSE;
|
||||
dibi::notify($this, 'commit');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if (!$this->inTxn) {
|
||||
throw new DibiException('There is no active transaction.');
|
||||
}
|
||||
$this->driver->rollback();
|
||||
$this->inTxn = FALSE;
|
||||
dibi::notify($this, 'rollback');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
*
|
||||
* @param string unescaped string
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string escaped and quoted string
|
||||
*/
|
||||
public function escape($value, $type = dibi::FIELD_TEXT)
|
||||
{
|
||||
$this->connect(); // MySQL & PDO require connection
|
||||
return $this->driver->escape($value, $type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
*
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
*/
|
||||
public function unescape($value, $type = dibi::FIELD_BINARY)
|
||||
{
|
||||
return $this->driver->unescape($value, $type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Delimites identifier (table's or column's name, etc.).
|
||||
*
|
||||
* @param string identifier
|
||||
* @return string delimited identifier
|
||||
*/
|
||||
public function delimite($value)
|
||||
{
|
||||
return $this->driver->escape($value, dibi::IDENTIFIER);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
*
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
$this->driver->applyLimit($sql, $limit, $offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Import SQL dump from file - extreme fast!
|
||||
*
|
||||
* @param string filename
|
||||
* @return int count of sql commands
|
||||
*/
|
||||
public function loadFile($file)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
@set_time_limit(0); // intentionally @
|
||||
|
||||
$handle = @fopen($file, 'r'); // intentionally @
|
||||
if (!$handle) {
|
||||
throw new FileNotFoundException("Cannot open file '$file'.");
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$sql = '';
|
||||
while (!feof($handle)) {
|
||||
$s = fgets($handle);
|
||||
$sql .= $s;
|
||||
if (substr(rtrim($s), -1) === ';') {
|
||||
$this->driver->query($sql);
|
||||
$sql = '';
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a information of the current database.
|
||||
*
|
||||
* @return DibiReflection
|
||||
*/
|
||||
public function getDibiReflection()
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prevents unserialization.
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prevents serialization.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,92 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of IDataSource for dibi.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
class DibiDataSource extends /*Nette::*/Object implements IDataSource
|
||||
{
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
/** @var int */
|
||||
private $count;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string SQL command or table name, as data source
|
||||
* @param DibiConnection connection
|
||||
*/
|
||||
public function __construct($sql, DibiConnection $connection = NULL)
|
||||
{
|
||||
if (strpos($sql, ' ') === FALSE) {
|
||||
// table name
|
||||
$this->sql = $sql;
|
||||
} else {
|
||||
// SQL command
|
||||
$this->sql = '(' . $sql . ') AS [source]';
|
||||
}
|
||||
|
||||
$this->connection = $connection === NULL ? dibi::getConnection() : $connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param int offset
|
||||
* @param int limit
|
||||
* @param array columns
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
public function getIterator($offset = NULL, $limit = NULL, $cols = NULL)
|
||||
{
|
||||
return $this->connection->query('
|
||||
SELECT *
|
||||
FROM', $this->sql, '
|
||||
%ofs %lmt', $offset, $limit
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
if ($this->count === NULL) {
|
||||
$this->count = $this->connection->query('
|
||||
SELECT COUNT(*) FROM', $this->sql
|
||||
)->fetchSingle();
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of IDataSource for dibi.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiDataSource extends /*Nette::*/Object implements IDataSource
|
||||
{
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
/** @var int */
|
||||
private $count;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string SQL command or table name, as data source
|
||||
* @param DibiConnection connection
|
||||
*/
|
||||
public function __construct($sql, DibiConnection $connection = NULL)
|
||||
{
|
||||
if (strpos($sql, ' ') === FALSE) {
|
||||
// table name
|
||||
$this->sql = $sql;
|
||||
} else {
|
||||
// SQL command
|
||||
$this->sql = '(' . $sql . ') AS [source]';
|
||||
}
|
||||
|
||||
$this->connection = $connection === NULL ? dibi::getConnection() : $connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param int offset
|
||||
* @param int limit
|
||||
* @param array columns
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
public function getIterator($offset = NULL, $limit = NULL, $cols = NULL)
|
||||
{
|
||||
return $this->connection->query('
|
||||
SELECT *
|
||||
FROM', $this->sql, '
|
||||
%ofs %lmt', $offset, $limit
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
if ($this->count === NULL) {
|
||||
$this->count = $this->connection->query('
|
||||
SELECT COUNT(*) FROM', $this->sql
|
||||
)->fetchSingle();
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,159 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi common exception.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
class DibiException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* database server exception.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
class DibiDriverException extends DibiException implements /*Nette::*/IDebuggable
|
||||
{
|
||||
/** @var string */
|
||||
private static $errorMsg;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
|
||||
/**
|
||||
* Construct an dibi driver exception.
|
||||
*
|
||||
* @param string Message describing the exception
|
||||
* @param int Some code
|
||||
* @param string SQL command
|
||||
*/
|
||||
public function __construct($message = NULL, $code = 0, $sql = NULL)
|
||||
{
|
||||
parent::__construct($message, (int) $code);
|
||||
$this->sql = $sql;
|
||||
dibi::notify(NULL, 'exception', $this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string The SQL passed to the constructor
|
||||
*/
|
||||
final public function getSql()
|
||||
{
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string string represenation of exception with SQL command
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return parent::__toString() . ($this->sql ? "\nSQL: " . $this->sql : '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* interface Nette::IDebuggable ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Returns custom panels.
|
||||
* @return array
|
||||
*/
|
||||
public function getPanels()
|
||||
{
|
||||
$panels = array();
|
||||
if ($this->sql !== NULL) {
|
||||
$panels['SQL'] = array(
|
||||
'expanded' => TRUE,
|
||||
'content' => dibi::dump($this->sql, TRUE),
|
||||
);
|
||||
}
|
||||
return $panels;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* error catching ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starts catching potential errors/warnings
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function tryError()
|
||||
{
|
||||
set_error_handler(array(__CLASS__, '_errorHandler'), E_ALL);
|
||||
self::$errorMsg = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns catched error/warning message.
|
||||
*
|
||||
* @param string catched message
|
||||
* @return bool
|
||||
*/
|
||||
public static function catchError(& $message)
|
||||
{
|
||||
restore_error_handler();
|
||||
$message = self::$errorMsg;
|
||||
self::$errorMsg = NULL;
|
||||
return $message !== NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal error handler. Do not call directly.
|
||||
*/
|
||||
public static function _errorHandler($code, $message)
|
||||
{
|
||||
restore_error_handler();
|
||||
|
||||
if (ini_get('html_errors')) {
|
||||
$message = strip_tags($message);
|
||||
$message = html_entity_decode($message);
|
||||
}
|
||||
|
||||
self::$errorMsg = $message;
|
||||
}
|
||||
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi common exception.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* database server exception.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiDriverException extends DibiException implements /*Nette::*/IDebuggable
|
||||
{
|
||||
/** @var string */
|
||||
private static $errorMsg;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
|
||||
/**
|
||||
* Construct an dibi driver exception.
|
||||
*
|
||||
* @param string Message describing the exception
|
||||
* @param int Some code
|
||||
* @param string SQL command
|
||||
*/
|
||||
public function __construct($message = NULL, $code = 0, $sql = NULL)
|
||||
{
|
||||
parent::__construct($message, (int) $code);
|
||||
$this->sql = $sql;
|
||||
dibi::notify(NULL, 'exception', $this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string The SQL passed to the constructor
|
||||
*/
|
||||
final public function getSql()
|
||||
{
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string string represenation of exception with SQL command
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return parent::__toString() . ($this->sql ? "\nSQL: " . $this->sql : '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* interface Nette::IDebuggable ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Returns custom panels.
|
||||
* @return array
|
||||
*/
|
||||
public function getPanels()
|
||||
{
|
||||
$panels = array();
|
||||
if ($this->sql !== NULL) {
|
||||
$panels['SQL'] = array(
|
||||
'expanded' => TRUE,
|
||||
'content' => dibi::dump($this->sql, TRUE),
|
||||
);
|
||||
}
|
||||
return $panels;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* error catching ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starts catching potential errors/warnings
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function tryError()
|
||||
{
|
||||
set_error_handler(array(__CLASS__, '_errorHandler'), E_ALL);
|
||||
self::$errorMsg = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns catched error/warning message.
|
||||
*
|
||||
* @param string catched message
|
||||
* @return bool
|
||||
*/
|
||||
public static function catchError(& $message)
|
||||
{
|
||||
restore_error_handler();
|
||||
$message = self::$errorMsg;
|
||||
self::$errorMsg = NULL;
|
||||
return $message !== NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal error handler. Do not call directly.
|
||||
*/
|
||||
public static function _errorHandler($code, $message)
|
||||
{
|
||||
restore_error_handler();
|
||||
|
||||
if (ini_get('html_errors')) {
|
||||
$message = strip_tags($message);
|
||||
$message = html_entity_decode($message);
|
||||
}
|
||||
|
||||
self::$errorMsg = $message;
|
||||
}
|
||||
|
||||
}
|
@@ -1,329 +1,329 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi SQL builder via fluent interfaces. EXPERIMENTAL!
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
class DibiFluent extends /*Nette::*/Object
|
||||
{
|
||||
/** @var array */
|
||||
public static $masks = array(
|
||||
'SELECT' => array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'GROUP BY',
|
||||
'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET', '%end'),
|
||||
'UPDATE' => array('UPDATE', 'SET', 'WHERE', 'ORDER BY', 'LIMIT', '%end'),
|
||||
'INSERT' => array('INSERT', 'INTO', 'VALUES', 'SELECT', '%end'),
|
||||
'DELETE' => array('DELETE', 'FROM', 'USING', 'WHERE', 'ORDER BY', 'LIMIT', '%end'),
|
||||
);
|
||||
|
||||
/** @var array */
|
||||
public static $separators = array(
|
||||
'SELECT' => ',',
|
||||
'FROM' => FALSE,
|
||||
'WHERE' => 'AND',
|
||||
'GROUP BY' => ',',
|
||||
'HAVING' => 'AND',
|
||||
'ORDER BY' => ',',
|
||||
'LIMIT' => FALSE,
|
||||
'OFFSET' => FALSE,
|
||||
'SET' => ',',
|
||||
'VALUES' => ',',
|
||||
'INTO' => FALSE,
|
||||
);
|
||||
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $command;
|
||||
|
||||
/** @var array */
|
||||
private $clauses = array();
|
||||
|
||||
/** @var array */
|
||||
private $flags = array();
|
||||
|
||||
/** @var array */
|
||||
private $cursor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param DibiConnection
|
||||
*/
|
||||
public function __construct(DibiConnection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends new argument to the clause.
|
||||
* @param string clause name
|
||||
* @param array arguments
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function __call($clause, $args)
|
||||
{
|
||||
$clause = self::_clause($clause);
|
||||
|
||||
// lazy initialization
|
||||
if ($this->command === NULL) {
|
||||
if (isset(self::$masks[$clause])) {
|
||||
$this->clauses = array_fill_keys(self::$masks[$clause], NULL);
|
||||
}
|
||||
$this->cursor = & $this->clauses[$clause];
|
||||
$this->cursor = array();
|
||||
$this->command = $clause;
|
||||
}
|
||||
|
||||
// special types or argument
|
||||
if (count($args) === 1) {
|
||||
$arg = $args[0];
|
||||
// TODO: really ignore TRUE?
|
||||
if ($arg === TRUE) {
|
||||
$args = array();
|
||||
|
||||
} elseif (is_string($arg) && preg_match('#^[a-z][a-z0-9_.]*$#i', $arg)) {
|
||||
$args = array('%n', $arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($clause, $this->clauses)) {
|
||||
// append to clause
|
||||
$this->cursor = & $this->clauses[$clause];
|
||||
|
||||
// TODO: really delete?
|
||||
if ($args === array(FALSE)) {
|
||||
$this->cursor = NULL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (isset(self::$separators[$clause])) {
|
||||
$sep = self::$separators[$clause];
|
||||
if ($sep === FALSE) {
|
||||
$this->cursor = array();
|
||||
|
||||
} elseif (!empty($this->cursor)) {
|
||||
$this->cursor[] = $sep;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// append to currect flow
|
||||
if ($args === array(FALSE)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->cursor[] = $clause;
|
||||
}
|
||||
|
||||
if ($this->cursor === NULL) {
|
||||
$this->cursor = array();
|
||||
}
|
||||
|
||||
array_splice($this->cursor, count($this->cursor), 0, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switch to a clause.
|
||||
* @param string clause name
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function clause($clause, $remove = FALSE)
|
||||
{
|
||||
$this->cursor = & $this->clauses[self::_clause($clause)];
|
||||
|
||||
if ($remove) {
|
||||
$this->cursor = NULL;
|
||||
|
||||
} elseif ($this->cursor === NULL) {
|
||||
$this->cursor = array();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change a SQL flag.
|
||||
* @param string flag name
|
||||
* @param bool value
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function setFlag($flag, $value = TRUE)
|
||||
{
|
||||
$flag = strtoupper($flag);
|
||||
if ($value) {
|
||||
$this->flags[$flag] = TRUE;
|
||||
} else {
|
||||
unset($this->flags[$flag]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is a flag set?
|
||||
* @param string flag name
|
||||
* @return bool
|
||||
*/
|
||||
final public function getFlag($flag, $value = TRUE)
|
||||
{
|
||||
return isset($this->flags[strtoupper($flag)]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns SQL command.
|
||||
* @return string
|
||||
*/
|
||||
final public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and executes SQL query.
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
return $this->connection->query($this->_export());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates, executes SQL query and fetches the single row.
|
||||
* @return array|FALSE array on success, FALSE if no next record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function fetch()
|
||||
{
|
||||
if ($this->command === 'SELECT') {
|
||||
$this->clauses['LIMIT'] = array(1);
|
||||
}
|
||||
return $this->connection->query($this->_export())->fetch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and prints SQL query or it's part.
|
||||
* @param string clause name
|
||||
* @return bool
|
||||
*/
|
||||
public function test($clause = NULL)
|
||||
{
|
||||
return $this->connection->test($this->_export($clause));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates parameters for DibiTranslator.
|
||||
* @param string clause name
|
||||
* @return array
|
||||
*/
|
||||
protected function _export($clause = NULL)
|
||||
{
|
||||
if ($clause === NULL) {
|
||||
$data = $this->clauses;
|
||||
|
||||
} else {
|
||||
$clause = self::_clause($clause);
|
||||
if (array_key_exists($clause, $this->clauses)) {
|
||||
$data = array($clause => $this->clauses[$clause]);
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
$args = array();
|
||||
foreach ($data as $clause => $statement) {
|
||||
if ($statement !== NULL) {
|
||||
if ($clause[0] !== '%') {
|
||||
$args[] = $clause;
|
||||
if ($clause === $this->command) {
|
||||
$args[] = implode(' ', array_keys($this->flags));
|
||||
}
|
||||
}
|
||||
array_splice($args, count($args), 0, $statement);
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Format camelCase clause name to UPPER CASE.
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
private static function _clause($s)
|
||||
{
|
||||
if ($s === 'order' || $s === 'group') {
|
||||
$s .= 'By';
|
||||
trigger_error("Did you mean '$s'?", E_USER_NOTICE);
|
||||
}
|
||||
return strtoupper(preg_replace('#[A-Z]#', ' $0', $s));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns (highlighted) SQL query.
|
||||
* @return string
|
||||
*/
|
||||
final public function __toString()
|
||||
{
|
||||
ob_start();
|
||||
$this->test();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// PHP < 5.2 compatibility
|
||||
if (!function_exists('array_fill_keys')) {
|
||||
function array_fill_keys($keys, $value)
|
||||
{
|
||||
return array_combine($keys, array_fill(0, count($keys), $value));
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi SQL builder via fluent interfaces. EXPERIMENTAL!
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiFluent extends /*Nette::*/Object
|
||||
{
|
||||
/** @var array */
|
||||
public static $masks = array(
|
||||
'SELECT' => array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'GROUP BY',
|
||||
'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET', '%end'),
|
||||
'UPDATE' => array('UPDATE', 'SET', 'WHERE', 'ORDER BY', 'LIMIT', '%end'),
|
||||
'INSERT' => array('INSERT', 'INTO', 'VALUES', 'SELECT', '%end'),
|
||||
'DELETE' => array('DELETE', 'FROM', 'USING', 'WHERE', 'ORDER BY', 'LIMIT', '%end'),
|
||||
);
|
||||
|
||||
/** @var array */
|
||||
public static $separators = array(
|
||||
'SELECT' => ',',
|
||||
'FROM' => FALSE,
|
||||
'WHERE' => 'AND',
|
||||
'GROUP BY' => ',',
|
||||
'HAVING' => 'AND',
|
||||
'ORDER BY' => ',',
|
||||
'LIMIT' => FALSE,
|
||||
'OFFSET' => FALSE,
|
||||
'SET' => ',',
|
||||
'VALUES' => ',',
|
||||
'INTO' => FALSE,
|
||||
);
|
||||
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $command;
|
||||
|
||||
/** @var array */
|
||||
private $clauses = array();
|
||||
|
||||
/** @var array */
|
||||
private $flags = array();
|
||||
|
||||
/** @var array */
|
||||
private $cursor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param DibiConnection
|
||||
*/
|
||||
public function __construct(DibiConnection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends new argument to the clause.
|
||||
* @param string clause name
|
||||
* @param array arguments
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function __call($clause, $args)
|
||||
{
|
||||
$clause = self::_clause($clause);
|
||||
|
||||
// lazy initialization
|
||||
if ($this->command === NULL) {
|
||||
if (isset(self::$masks[$clause])) {
|
||||
$this->clauses = array_fill_keys(self::$masks[$clause], NULL);
|
||||
}
|
||||
$this->cursor = & $this->clauses[$clause];
|
||||
$this->cursor = array();
|
||||
$this->command = $clause;
|
||||
}
|
||||
|
||||
// special types or argument
|
||||
if (count($args) === 1) {
|
||||
$arg = $args[0];
|
||||
// TODO: really ignore TRUE?
|
||||
if ($arg === TRUE) {
|
||||
$args = array();
|
||||
|
||||
} elseif (is_string($arg) && preg_match('#^[a-z][a-z0-9_.]*$#i', $arg)) {
|
||||
$args = array('%n', $arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($clause, $this->clauses)) {
|
||||
// append to clause
|
||||
$this->cursor = & $this->clauses[$clause];
|
||||
|
||||
// TODO: really delete?
|
||||
if ($args === array(FALSE)) {
|
||||
$this->cursor = NULL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (isset(self::$separators[$clause])) {
|
||||
$sep = self::$separators[$clause];
|
||||
if ($sep === FALSE) {
|
||||
$this->cursor = array();
|
||||
|
||||
} elseif (!empty($this->cursor)) {
|
||||
$this->cursor[] = $sep;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// append to currect flow
|
||||
if ($args === array(FALSE)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->cursor[] = $clause;
|
||||
}
|
||||
|
||||
if ($this->cursor === NULL) {
|
||||
$this->cursor = array();
|
||||
}
|
||||
|
||||
array_splice($this->cursor, count($this->cursor), 0, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switch to a clause.
|
||||
* @param string clause name
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function clause($clause, $remove = FALSE)
|
||||
{
|
||||
$this->cursor = & $this->clauses[self::_clause($clause)];
|
||||
|
||||
if ($remove) {
|
||||
$this->cursor = NULL;
|
||||
|
||||
} elseif ($this->cursor === NULL) {
|
||||
$this->cursor = array();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change a SQL flag.
|
||||
* @param string flag name
|
||||
* @param bool value
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function setFlag($flag, $value = TRUE)
|
||||
{
|
||||
$flag = strtoupper($flag);
|
||||
if ($value) {
|
||||
$this->flags[$flag] = TRUE;
|
||||
} else {
|
||||
unset($this->flags[$flag]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is a flag set?
|
||||
* @param string flag name
|
||||
* @return bool
|
||||
*/
|
||||
final public function getFlag($flag, $value = TRUE)
|
||||
{
|
||||
return isset($this->flags[strtoupper($flag)]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns SQL command.
|
||||
* @return string
|
||||
*/
|
||||
final public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and executes SQL query.
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
return $this->connection->query($this->_export());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates, executes SQL query and fetches the single row.
|
||||
* @return array|FALSE array on success, FALSE if no next record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function fetch()
|
||||
{
|
||||
if ($this->command === 'SELECT') {
|
||||
$this->clauses['LIMIT'] = array(1);
|
||||
}
|
||||
return $this->connection->query($this->_export())->fetch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and prints SQL query or it's part.
|
||||
* @param string clause name
|
||||
* @return bool
|
||||
*/
|
||||
public function test($clause = NULL)
|
||||
{
|
||||
return $this->connection->test($this->_export($clause));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates parameters for DibiTranslator.
|
||||
* @param string clause name
|
||||
* @return array
|
||||
*/
|
||||
protected function _export($clause = NULL)
|
||||
{
|
||||
if ($clause === NULL) {
|
||||
$data = $this->clauses;
|
||||
|
||||
} else {
|
||||
$clause = self::_clause($clause);
|
||||
if (array_key_exists($clause, $this->clauses)) {
|
||||
$data = array($clause => $this->clauses[$clause]);
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
$args = array();
|
||||
foreach ($data as $clause => $statement) {
|
||||
if ($statement !== NULL) {
|
||||
if ($clause[0] !== '%') {
|
||||
$args[] = $clause;
|
||||
if ($clause === $this->command) {
|
||||
$args[] = implode(' ', array_keys($this->flags));
|
||||
}
|
||||
}
|
||||
array_splice($args, count($args), 0, $statement);
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Format camelCase clause name to UPPER CASE.
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
private static function _clause($s)
|
||||
{
|
||||
if ($s === 'order' || $s === 'group') {
|
||||
$s .= 'By';
|
||||
trigger_error("Did you mean '$s'?", E_USER_NOTICE);
|
||||
}
|
||||
return strtoupper(preg_replace('#[A-Z]#', ' $0', $s));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns (highlighted) SQL query.
|
||||
* @return string
|
||||
*/
|
||||
final public function __toString()
|
||||
{
|
||||
ob_start();
|
||||
$this->test();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// PHP < 5.2 compatibility
|
||||
if (!function_exists('array_fill_keys')) {
|
||||
function array_fill_keys($keys, $value)
|
||||
{
|
||||
return array_combine($keys, array_fill(0, count($keys), $value));
|
||||
}
|
||||
}
|
||||
|
@@ -1,106 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi basic logger & profiler (experimental).
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
final class DibiLogger extends /*Nette::*/Object
|
||||
{
|
||||
/** @var string Name of the file where SQL errors should be logged */
|
||||
private $file;
|
||||
|
||||
/** @var bool */
|
||||
public $logErrors = TRUE;
|
||||
|
||||
/** @var bool */
|
||||
public $logQueries = TRUE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string filename
|
||||
*/
|
||||
public function __construct($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Event handler (events: exception, connected, beforeQuery, afterQuery, begin, commit, rollback).
|
||||
*
|
||||
* @param DibiConnection
|
||||
* @param string event name
|
||||
* @param mixed
|
||||
* @return void
|
||||
*/
|
||||
public function handler($connection, $event, $arg)
|
||||
{
|
||||
if ($event === 'afterQuery' && $this->logQueries) {
|
||||
$this->write(
|
||||
"OK: " . dibi::$sql
|
||||
. ($arg instanceof DibiResult ? ";\n-- rows: " . count($arg) : '')
|
||||
. "\n-- takes: " . sprintf('%0.3f', dibi::$elapsedTime * 1000) . ' ms'
|
||||
. "\n-- driver: " . $connection->getConfig('driver')
|
||||
. "\n-- " . date('Y-m-d H:i:s')
|
||||
. "\n\n"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event === 'exception' && $this->logErrors) {
|
||||
// $arg is DibiDriverException
|
||||
$message = $arg->getMessage();
|
||||
$code = $arg->getCode();
|
||||
if ($code) {
|
||||
$message = "[$code] $message";
|
||||
}
|
||||
|
||||
$this->write(
|
||||
"ERROR: $message"
|
||||
. "\n-- SQL: " . dibi::$sql
|
||||
. "\n-- driver: " //. $connection->getConfig('driver')
|
||||
. ";\n-- " . date('Y-m-d H:i:s')
|
||||
. "\n\n"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function write($message)
|
||||
{
|
||||
$handle = fopen($this->file, 'a');
|
||||
if (!$handle) return; // or throw exception?
|
||||
|
||||
flock($handle, LOCK_EX);
|
||||
fwrite($handle, $message);
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi basic logger & profiler (experimental).
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
final class DibiLogger extends /*Nette::*/Object
|
||||
{
|
||||
/** @var string Name of the file where SQL errors should be logged */
|
||||
private $file;
|
||||
|
||||
/** @var bool */
|
||||
public $logErrors = TRUE;
|
||||
|
||||
/** @var bool */
|
||||
public $logQueries = TRUE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string filename
|
||||
*/
|
||||
public function __construct($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Event handler (events: exception, connected, beforeQuery, afterQuery, begin, commit, rollback).
|
||||
*
|
||||
* @param DibiConnection
|
||||
* @param string event name
|
||||
* @param mixed
|
||||
* @return void
|
||||
*/
|
||||
public function handler($connection, $event, $arg)
|
||||
{
|
||||
if ($event === 'afterQuery' && $this->logQueries) {
|
||||
$this->write(
|
||||
"OK: " . dibi::$sql
|
||||
. ($arg instanceof DibiResult ? ";\n-- rows: " . count($arg) : '')
|
||||
. "\n-- takes: " . sprintf('%0.3f', dibi::$elapsedTime * 1000) . ' ms'
|
||||
. "\n-- driver: " . $connection->getConfig('driver')
|
||||
. "\n-- " . date('Y-m-d H:i:s')
|
||||
. "\n\n"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event === 'exception' && $this->logErrors) {
|
||||
// $arg is DibiDriverException
|
||||
$message = $arg->getMessage();
|
||||
$code = $arg->getCode();
|
||||
if ($code) {
|
||||
$message = "[$code] $message";
|
||||
}
|
||||
|
||||
$this->write(
|
||||
"ERROR: $message"
|
||||
. "\n-- SQL: " . dibi::$sql
|
||||
. "\n-- driver: " //. $connection->getConfig('driver')
|
||||
. ";\n-- " . date('Y-m-d H:i:s')
|
||||
. "\n\n"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function write($message)
|
||||
{
|
||||
$handle = fopen($this->file, 'a');
|
||||
if (!$handle) return; // or throw exception?
|
||||
|
||||
flock($handle, LOCK_EX);
|
||||
fwrite($handle, $message);
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,290 +1,290 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Experimental object-oriented interface to database tables.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
abstract class DibiTable extends /*Nette::*/Object
|
||||
{
|
||||
/** @var string primary key mask */
|
||||
public static $primaryMask = 'id';
|
||||
|
||||
/** @var bool */
|
||||
public static $lowerCase = TRUE;
|
||||
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string table name */
|
||||
protected $name;
|
||||
|
||||
/** @var string primary key name */
|
||||
protected $primary;
|
||||
|
||||
/** @var string primary key type */
|
||||
protected $primaryModifier = '%i';
|
||||
|
||||
/** @var array */
|
||||
protected $blankRow = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Table constructor.
|
||||
* @param DibiConnection
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(DibiConnection $connection = NULL)
|
||||
{
|
||||
$this->connection = $connection === NULL ? dibi::getConnection() : $connection;
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the table name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the primary key name.
|
||||
* @return string
|
||||
*/
|
||||
public function getPrimary()
|
||||
{
|
||||
return $this->primary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the dibi connection.
|
||||
* @return DibiConnection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup object.
|
||||
* @return void
|
||||
*/
|
||||
protected function setup()
|
||||
{
|
||||
// autodetect table name
|
||||
if ($this->name === NULL) {
|
||||
$name = $this->getClass();
|
||||
if (FALSE !== ($pos = strrpos($name, ':'))) {
|
||||
$name = substr($name, $pos + 1);
|
||||
}
|
||||
if (self::$lowerCase) {
|
||||
$name = strtolower($name);
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
// autodetect primary key name
|
||||
if ($this->primary === NULL) {
|
||||
$this->primary = str_replace(
|
||||
array('%p', '%s'),
|
||||
array($this->name, trim($this->name, 's')), // the simplest inflector in the world :-))
|
||||
self::$primaryMask
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Inserts row into a table.
|
||||
* @param array|object
|
||||
* @return int new primary key
|
||||
*/
|
||||
public function insert($data)
|
||||
{
|
||||
$this->connection->query(
|
||||
'INSERT INTO %n', $this->name, '%v', $this->prepare($data)
|
||||
);
|
||||
return $this->connection->insertId();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates rows in a table.
|
||||
* @param mixed primary key value(s)
|
||||
* @param array|object
|
||||
* @return int number of updated rows
|
||||
*/
|
||||
public function update($where, $data)
|
||||
{
|
||||
$this->connection->query(
|
||||
'UPDATE %n', $this->name,
|
||||
'SET %a', $this->prepare($data),
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
return $this->connection->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Deletes rows from a table by primary key.
|
||||
* @param mixed primary key value(s)
|
||||
* @return int number of deleted rows
|
||||
*/
|
||||
public function delete($where)
|
||||
{
|
||||
$this->connection->query(
|
||||
'DELETE FROM %n', $this->name,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
return $this->connection->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Finds rows by primary key.
|
||||
* @param mixed primary key value(s)
|
||||
* @return DibiResult
|
||||
*/
|
||||
public function find($what)
|
||||
{
|
||||
if (!is_array($what)) {
|
||||
$what = func_get_args();
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $what, ')'
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Selects all rows.
|
||||
* @param string column to order by
|
||||
* @return DibiResult
|
||||
*/
|
||||
public function findAll($order = NULL)
|
||||
{
|
||||
if ($order === NULL) {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name
|
||||
));
|
||||
} else {
|
||||
$order = func_get_args();
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'ORDER BY %n', $order
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches single row.
|
||||
* @param scalar|array primary key value
|
||||
* @return array|object row
|
||||
*/
|
||||
public function fetch($conditions)
|
||||
{
|
||||
if (is_array($conditions)) {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %and', $conditions
|
||||
))->fetch();
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %n=' . $this->primaryModifier, $this->primary, $conditions
|
||||
))->fetch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a blank row (not fetched from database).
|
||||
* @return array|object
|
||||
*/
|
||||
public function createBlank()
|
||||
{
|
||||
$row = $this->blankRow;
|
||||
$row[$this->primary] = NULL;
|
||||
|
||||
if ($class = $this->connection->getConfig('result:objects')) {
|
||||
if ($class === TRUE) {
|
||||
$row = (object) $row;
|
||||
} else {
|
||||
$row = new $class($row);
|
||||
}
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* User data pre-processing.
|
||||
* @param array|object
|
||||
* @return array
|
||||
*/
|
||||
protected function prepare($data)
|
||||
{
|
||||
if (is_object($data)) {
|
||||
return (array) $data;
|
||||
} elseif (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Dataset must be array or anonymous object.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* User DibiResult post-processing.
|
||||
* @param DibiResult
|
||||
* @return DibiResult
|
||||
*/
|
||||
protected function complete($res)
|
||||
{
|
||||
return $res;
|
||||
}
|
||||
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Experimental object-oriented interface to database tables.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
abstract class DibiTable extends /*Nette::*/Object
|
||||
{
|
||||
/** @var string primary key mask */
|
||||
public static $primaryMask = 'id';
|
||||
|
||||
/** @var bool */
|
||||
public static $lowerCase = TRUE;
|
||||
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string table name */
|
||||
protected $name;
|
||||
|
||||
/** @var string primary key name */
|
||||
protected $primary;
|
||||
|
||||
/** @var string primary key type */
|
||||
protected $primaryModifier = '%i';
|
||||
|
||||
/** @var array */
|
||||
protected $blankRow = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Table constructor.
|
||||
* @param DibiConnection
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(DibiConnection $connection = NULL)
|
||||
{
|
||||
$this->connection = $connection === NULL ? dibi::getConnection() : $connection;
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the table name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the primary key name.
|
||||
* @return string
|
||||
*/
|
||||
public function getPrimary()
|
||||
{
|
||||
return $this->primary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the dibi connection.
|
||||
* @return DibiConnection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup object.
|
||||
* @return void
|
||||
*/
|
||||
protected function setup()
|
||||
{
|
||||
// autodetect table name
|
||||
if ($this->name === NULL) {
|
||||
$name = $this->getClass();
|
||||
if (FALSE !== ($pos = strrpos($name, ':'))) {
|
||||
$name = substr($name, $pos + 1);
|
||||
}
|
||||
if (self::$lowerCase) {
|
||||
$name = strtolower($name);
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
// autodetect primary key name
|
||||
if ($this->primary === NULL) {
|
||||
$this->primary = str_replace(
|
||||
array('%p', '%s'),
|
||||
array($this->name, trim($this->name, 's')), // the simplest inflector in the world :-))
|
||||
self::$primaryMask
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Inserts row into a table.
|
||||
* @param array|object
|
||||
* @return int new primary key
|
||||
*/
|
||||
public function insert($data)
|
||||
{
|
||||
$this->connection->query(
|
||||
'INSERT INTO %n', $this->name, '%v', $this->prepare($data)
|
||||
);
|
||||
return $this->connection->insertId();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates rows in a table.
|
||||
* @param mixed primary key value(s)
|
||||
* @param array|object
|
||||
* @return int number of updated rows
|
||||
*/
|
||||
public function update($where, $data)
|
||||
{
|
||||
$this->connection->query(
|
||||
'UPDATE %n', $this->name,
|
||||
'SET %a', $this->prepare($data),
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
return $this->connection->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Deletes rows from a table by primary key.
|
||||
* @param mixed primary key value(s)
|
||||
* @return int number of deleted rows
|
||||
*/
|
||||
public function delete($where)
|
||||
{
|
||||
$this->connection->query(
|
||||
'DELETE FROM %n', $this->name,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
return $this->connection->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Finds rows by primary key.
|
||||
* @param mixed primary key value(s)
|
||||
* @return DibiResult
|
||||
*/
|
||||
public function find($what)
|
||||
{
|
||||
if (!is_array($what)) {
|
||||
$what = func_get_args();
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $what, ')'
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Selects all rows.
|
||||
* @param string column to order by
|
||||
* @return DibiResult
|
||||
*/
|
||||
public function findAll($order = NULL)
|
||||
{
|
||||
if ($order === NULL) {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name
|
||||
));
|
||||
} else {
|
||||
$order = func_get_args();
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'ORDER BY %n', $order
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches single row.
|
||||
* @param scalar|array primary key value
|
||||
* @return array|object row
|
||||
*/
|
||||
public function fetch($conditions)
|
||||
{
|
||||
if (is_array($conditions)) {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %and', $conditions
|
||||
))->fetch();
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %n=' . $this->primaryModifier, $this->primary, $conditions
|
||||
))->fetch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a blank row (not fetched from database).
|
||||
* @return array|object
|
||||
*/
|
||||
public function createBlank()
|
||||
{
|
||||
$row = $this->blankRow;
|
||||
$row[$this->primary] = NULL;
|
||||
|
||||
if ($class = $this->connection->getConfig('result:objects')) {
|
||||
if ($class === TRUE) {
|
||||
$row = (object) $row;
|
||||
} else {
|
||||
$row = new $class($row);
|
||||
}
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* User data pre-processing.
|
||||
* @param array|object
|
||||
* @return array
|
||||
*/
|
||||
protected function prepare($data)
|
||||
{
|
||||
if (is_object($data)) {
|
||||
return (array) $data;
|
||||
} elseif (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Dataset must be array or anonymous object.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* User DibiResult post-processing.
|
||||
* @param DibiResult
|
||||
* @return DibiResult
|
||||
*/
|
||||
protected function complete($res)
|
||||
{
|
||||
return $res;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,457 +1,457 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi SQL translator.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
final class DibiTranslator extends /*Nette::*/Object
|
||||
{
|
||||
/** @var string */
|
||||
public $sql;
|
||||
|
||||
/** @var IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @var int */
|
||||
private $cursor;
|
||||
|
||||
/** @var array */
|
||||
private $args;
|
||||
|
||||
/** @var bool */
|
||||
private $hasError;
|
||||
|
||||
/** @var bool */
|
||||
private $comment;
|
||||
|
||||
/** @var int */
|
||||
private $ifLevel;
|
||||
|
||||
/** @var int */
|
||||
private $ifLevelStart;
|
||||
|
||||
/** @var int */
|
||||
private $limit;
|
||||
|
||||
/** @var int */
|
||||
private $offset;
|
||||
|
||||
|
||||
|
||||
public function __construct(IDibiDriver $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* return IDibiDriver.
|
||||
*/
|
||||
public function getDriver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates SQL.
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
public function translate(array $args)
|
||||
{
|
||||
$this->limit = -1;
|
||||
$this->offset = 0;
|
||||
$this->hasError = FALSE;
|
||||
$commandIns = NULL;
|
||||
$lastArr = NULL;
|
||||
// shortcuts
|
||||
$cursor = & $this->cursor;
|
||||
$cursor = 0;
|
||||
$this->args = array_values($args);
|
||||
$args = & $this->args;
|
||||
|
||||
// conditional sql
|
||||
$this->ifLevel = $this->ifLevelStart = 0;
|
||||
$comment = & $this->comment;
|
||||
$comment = FALSE;
|
||||
|
||||
// iterate
|
||||
$sql = array();
|
||||
while ($cursor < count($args))
|
||||
{
|
||||
$arg = $args[$cursor];
|
||||
$cursor++;
|
||||
|
||||
// simple string means SQL
|
||||
if (is_string($arg)) {
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($arg, '`[\'"%');
|
||||
|
||||
if (strlen($arg) === $toSkip) { // needn't be translated
|
||||
$sql[] = $arg;
|
||||
} else {
|
||||
$sql[] = substr($arg, 0, $toSkip)
|
||||
/*
|
||||
preg_replace_callback('/
|
||||
(?=`|\[|\'|"|%) ## speed-up
|
||||
(?:
|
||||
`(.+?)`| ## 1) `identifier`
|
||||
\[(.+?)\]| ## 2) [identifier]
|
||||
(\')((?:\'\'|[^\'])*)\'| ## 3,4) string
|
||||
(")((?:""|[^"])*)"| ## 5,6) "string"
|
||||
(\'|") ## 7) lone-quote
|
||||
%([a-zA-Z]{1,4})(?![a-zA-Z])|## 8) modifier
|
||||
)/xs',
|
||||
*/ // note: this can change $this->args & $this->cursor & ...
|
||||
. preg_replace_callback('/(?=`|\[|\'|"|%)(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|%([a-zA-Z]{1,4})(?![a-zA-Z]))/s',
|
||||
array($this, 'cb'),
|
||||
substr($arg, $toSkip)
|
||||
);
|
||||
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comment) {
|
||||
$sql[] = '...';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($arg)) {
|
||||
if (is_string(key($arg))) {
|
||||
// associative array -> autoselect between SET or VALUES & LIST
|
||||
if ($commandIns === NULL) {
|
||||
$commandIns = strtoupper(substr(ltrim($args[0]), 0, 6));
|
||||
$commandIns = $commandIns === 'INSERT' || $commandIns === 'REPLAC';
|
||||
$sql[] = $this->formatValue($arg, $commandIns ? 'v' : 'a');
|
||||
} else {
|
||||
if ($lastArr === $cursor - 1) $sql[] = ',';
|
||||
$sql[] = $this->formatValue($arg, $commandIns ? 'l' : 'a');
|
||||
}
|
||||
$lastArr = $cursor;
|
||||
continue;
|
||||
|
||||
} elseif ($cursor === 1) {
|
||||
// implicit array expansion
|
||||
$cursor = 0;
|
||||
array_splice($args, 0, 1, $arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// default processing
|
||||
$sql[] = $this->formatValue($arg, FALSE);
|
||||
} // while
|
||||
|
||||
|
||||
if ($comment) $sql[] = "*/";
|
||||
|
||||
$sql = implode(' ', $sql);
|
||||
|
||||
// apply limit
|
||||
if ($this->limit > -1 || $this->offset > 0) {
|
||||
$this->driver->applyLimit($sql, $this->limit, $this->offset);
|
||||
}
|
||||
|
||||
$this->sql = $sql;
|
||||
return !$this->hasError;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply modifier to single value.
|
||||
* @param mixed
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function formatValue($value, $modifier)
|
||||
{
|
||||
// array processing (with or without modifier)
|
||||
if (is_array($value)) {
|
||||
|
||||
$vx = $kx = array();
|
||||
$separator = ', ';
|
||||
switch ($modifier) {
|
||||
case 'and':
|
||||
case 'or':
|
||||
$separator = ' ' . strtoupper($modifier) . ' ';
|
||||
if (!is_string(key($value))) {
|
||||
foreach ($value as $v) {
|
||||
$vx[] = $this->formatValue($v, 'sql');
|
||||
}
|
||||
return implode($separator, $vx);
|
||||
}
|
||||
// break intentionally omitted
|
||||
case 'a': // SET key=val, key=val, ...
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$vx[] = $this->delimite($pair[0]) . '='
|
||||
. $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return implode($separator, $vx);
|
||||
|
||||
|
||||
case 'l': // LIST (val, val, ...)
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return '(' . implode(', ', $vx) . ')';
|
||||
|
||||
|
||||
case 'v': // (key, key, ...) VALUES (val, val, ...)
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$kx[] = $this->delimite($pair[0]);
|
||||
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
|
||||
|
||||
default:
|
||||
foreach ($value as $v) {
|
||||
$vx[] = $this->formatValue($v, $modifier);
|
||||
}
|
||||
return implode(', ', $vx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// with modifier procession
|
||||
if ($modifier) {
|
||||
if ($value === NULL) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
if ($value instanceof IDibiVariable) {
|
||||
return $value->toSql($this, $modifier);
|
||||
}
|
||||
|
||||
if (!is_scalar($value)) { // array is already processed
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected type ' . gettype($value) . '**';
|
||||
}
|
||||
|
||||
switch ($modifier) {
|
||||
case 's': // string
|
||||
case 'bin':// binary
|
||||
case 'b': // boolean
|
||||
return $this->driver->escape($value, $modifier);
|
||||
|
||||
case 'sn': // string or NULL
|
||||
return $value == '' ? 'NULL' : $this->driver->escape($value, dibi::FIELD_TEXT); // notice two equal signs
|
||||
|
||||
case 'i': // signed int
|
||||
case 'u': // unsigned int, ignored
|
||||
// support for numbers - keep them unchanged
|
||||
if (is_string($value) && preg_match('#[+-]?\d+(e\d+)?$#A', $value)) {
|
||||
return $value;
|
||||
}
|
||||
return (string) (int) ($value + 0);
|
||||
|
||||
case 'f': // float
|
||||
// support for numbers - keep them unchanged
|
||||
if (is_numeric($value) && (!is_string($value) || strpos($value, 'x') === FALSE)) {
|
||||
return $value; // something like -9E-005 is accepted by SQL, HEX values is not
|
||||
}
|
||||
return (string) ($value + 0);
|
||||
|
||||
case 'd': // date
|
||||
case 't': // datetime
|
||||
return $this->driver->escape(is_string($value) ? strtotime($value) : $value, $modifier);
|
||||
|
||||
case 'n': // identifier name
|
||||
return $this->delimite($value);
|
||||
|
||||
case 'sql':// preserve as SQL
|
||||
$value = (string) $value;
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($value, '`[\'"');
|
||||
if (strlen($value) === $toSkip) { // needn't be translated
|
||||
return $value;
|
||||
} else {
|
||||
return substr($value, 0, $toSkip)
|
||||
. preg_replace_callback('/(?=`|\[|\'|")(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"(\'|"))/s',
|
||||
array($this, 'cb'),
|
||||
substr($value, $toSkip)
|
||||
);
|
||||
}
|
||||
|
||||
case 'and':
|
||||
case 'or':
|
||||
case 'a':
|
||||
case 'l':
|
||||
case 'v':
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected type ' . gettype($value) . '**';
|
||||
|
||||
default:
|
||||
$this->hasError = TRUE;
|
||||
return "**Unknown or invalid modifier %$modifier**";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// without modifier procession
|
||||
if (is_string($value))
|
||||
return $this->driver->escape($value, dibi::FIELD_TEXT);
|
||||
|
||||
if (is_int($value) || is_float($value))
|
||||
return (string) $value; // something like -9E-005 is accepted by SQL
|
||||
|
||||
if (is_bool($value))
|
||||
return $this->driver->escape($value, dibi::FIELD_BOOL);
|
||||
|
||||
if ($value === NULL)
|
||||
return 'NULL';
|
||||
|
||||
if ($value instanceof IDibiVariable)
|
||||
return $value->toSql($this, NULL);
|
||||
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected ' . gettype($value) . '**';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* PREG callback from translate() or formatValue().
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
private function cb($matches)
|
||||
{
|
||||
// [1] => `ident`
|
||||
// [2] => [ident]
|
||||
// [3] => '
|
||||
// [4] => string
|
||||
// [5] => "
|
||||
// [6] => string
|
||||
// [7] => lone-quote
|
||||
// [8] => modifier (when called from self::translate())
|
||||
|
||||
if (!empty($matches[8])) { // modifier
|
||||
$mod = $matches[8];
|
||||
$cursor = & $this->cursor;
|
||||
|
||||
if ($cursor >= count($this->args) && $mod !== 'else' && $mod !== 'end') {
|
||||
$this->hasError = TRUE;
|
||||
return "**Extra modifier %$mod**";
|
||||
}
|
||||
|
||||
if ($mod === 'if') {
|
||||
$this->ifLevel++;
|
||||
$cursor++;
|
||||
if (!$this->comment && !$this->args[$cursor - 1]) {
|
||||
// open comment
|
||||
$this->ifLevelStart = $this->ifLevel;
|
||||
$this->comment = TRUE;
|
||||
return "/*";
|
||||
}
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'else') {
|
||||
if ($this->ifLevelStart === $this->ifLevel) {
|
||||
$this->ifLevelStart = 0;
|
||||
$this->comment = FALSE;
|
||||
return "*/";
|
||||
} elseif (!$this->comment) {
|
||||
$this->ifLevelStart = $this->ifLevel;
|
||||
$this->comment = TRUE;
|
||||
return "/*";
|
||||
}
|
||||
|
||||
} elseif ($mod === 'end') {
|
||||
$this->ifLevel--;
|
||||
if ($this->ifLevelStart === $this->ifLevel + 1) {
|
||||
// close comment
|
||||
$this->ifLevelStart = 0;
|
||||
$this->comment = FALSE;
|
||||
return "*/";
|
||||
}
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'ex') { // array expansion
|
||||
array_splice($this->args, $cursor, 1, $this->args[$cursor]);
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'lmt') { // apply limit
|
||||
if ($this->args[$cursor] !== NULL) $this->limit = (int) $this->args[$cursor];
|
||||
$cursor++;
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'ofs') { // apply offset
|
||||
if ($this->args[$cursor] !== NULL) $this->offset = (int) $this->args[$cursor];
|
||||
$cursor++;
|
||||
return '';
|
||||
|
||||
} else { // default processing
|
||||
$cursor++;
|
||||
return $this->formatValue($this->args[$cursor - 1], $mod);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->comment) return '...';
|
||||
|
||||
if ($matches[1]) // SQL identifiers: `ident`
|
||||
return $this->delimite($matches[1]);
|
||||
|
||||
if ($matches[2]) // SQL identifiers: [ident]
|
||||
return $this->delimite($matches[2]);
|
||||
|
||||
if ($matches[3]) // SQL strings: '...'
|
||||
return $this->driver->escape( str_replace("''", "'", $matches[4]), dibi::FIELD_TEXT);
|
||||
|
||||
if ($matches[5]) // SQL strings: "..."
|
||||
return $this->driver->escape( str_replace('""', '"', $matches[6]), dibi::FIELD_TEXT);
|
||||
|
||||
if ($matches[7]) { // string quote
|
||||
$this->hasError = TRUE;
|
||||
return '**Alone quote**';
|
||||
}
|
||||
|
||||
die('this should be never executed');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply substitutions to indentifier and delimites it.
|
||||
*
|
||||
* @param string indentifier
|
||||
* @return string
|
||||
*/
|
||||
private function delimite($value)
|
||||
{
|
||||
return $this->driver->escape(dibi::substitute($value), dibi::IDENTIFIER);
|
||||
}
|
||||
|
||||
|
||||
} // class DibiTranslator
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi SQL translator.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
final class DibiTranslator extends /*Nette::*/Object
|
||||
{
|
||||
/** @var string */
|
||||
public $sql;
|
||||
|
||||
/** @var IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @var int */
|
||||
private $cursor;
|
||||
|
||||
/** @var array */
|
||||
private $args;
|
||||
|
||||
/** @var bool */
|
||||
private $hasError;
|
||||
|
||||
/** @var bool */
|
||||
private $comment;
|
||||
|
||||
/** @var int */
|
||||
private $ifLevel;
|
||||
|
||||
/** @var int */
|
||||
private $ifLevelStart;
|
||||
|
||||
/** @var int */
|
||||
private $limit;
|
||||
|
||||
/** @var int */
|
||||
private $offset;
|
||||
|
||||
|
||||
|
||||
public function __construct(IDibiDriver $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* return IDibiDriver.
|
||||
*/
|
||||
public function getDriver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates SQL.
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
public function translate(array $args)
|
||||
{
|
||||
$this->limit = -1;
|
||||
$this->offset = 0;
|
||||
$this->hasError = FALSE;
|
||||
$commandIns = NULL;
|
||||
$lastArr = NULL;
|
||||
// shortcuts
|
||||
$cursor = & $this->cursor;
|
||||
$cursor = 0;
|
||||
$this->args = array_values($args);
|
||||
$args = & $this->args;
|
||||
|
||||
// conditional sql
|
||||
$this->ifLevel = $this->ifLevelStart = 0;
|
||||
$comment = & $this->comment;
|
||||
$comment = FALSE;
|
||||
|
||||
// iterate
|
||||
$sql = array();
|
||||
while ($cursor < count($args))
|
||||
{
|
||||
$arg = $args[$cursor];
|
||||
$cursor++;
|
||||
|
||||
// simple string means SQL
|
||||
if (is_string($arg)) {
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($arg, '`[\'"%');
|
||||
|
||||
if (strlen($arg) === $toSkip) { // needn't be translated
|
||||
$sql[] = $arg;
|
||||
} else {
|
||||
$sql[] = substr($arg, 0, $toSkip)
|
||||
/*
|
||||
preg_replace_callback('/
|
||||
(?=`|\[|\'|"|%) ## speed-up
|
||||
(?:
|
||||
`(.+?)`| ## 1) `identifier`
|
||||
\[(.+?)\]| ## 2) [identifier]
|
||||
(\')((?:\'\'|[^\'])*)\'| ## 3,4) string
|
||||
(")((?:""|[^"])*)"| ## 5,6) "string"
|
||||
(\'|") ## 7) lone-quote
|
||||
%([a-zA-Z]{1,4})(?![a-zA-Z])|## 8) modifier
|
||||
)/xs',
|
||||
*/ // note: this can change $this->args & $this->cursor & ...
|
||||
. preg_replace_callback('/(?=`|\[|\'|"|%)(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|%([a-zA-Z]{1,4})(?![a-zA-Z]))/s',
|
||||
array($this, 'cb'),
|
||||
substr($arg, $toSkip)
|
||||
);
|
||||
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comment) {
|
||||
$sql[] = '...';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($arg)) {
|
||||
if (is_string(key($arg))) {
|
||||
// associative array -> autoselect between SET or VALUES & LIST
|
||||
if ($commandIns === NULL) {
|
||||
$commandIns = strtoupper(substr(ltrim($args[0]), 0, 6));
|
||||
$commandIns = $commandIns === 'INSERT' || $commandIns === 'REPLAC';
|
||||
$sql[] = $this->formatValue($arg, $commandIns ? 'v' : 'a');
|
||||
} else {
|
||||
if ($lastArr === $cursor - 1) $sql[] = ',';
|
||||
$sql[] = $this->formatValue($arg, $commandIns ? 'l' : 'a');
|
||||
}
|
||||
$lastArr = $cursor;
|
||||
continue;
|
||||
|
||||
} elseif ($cursor === 1) {
|
||||
// implicit array expansion
|
||||
$cursor = 0;
|
||||
array_splice($args, 0, 1, $arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// default processing
|
||||
$sql[] = $this->formatValue($arg, FALSE);
|
||||
} // while
|
||||
|
||||
|
||||
if ($comment) $sql[] = "*/";
|
||||
|
||||
$sql = implode(' ', $sql);
|
||||
|
||||
// apply limit
|
||||
if ($this->limit > -1 || $this->offset > 0) {
|
||||
$this->driver->applyLimit($sql, $this->limit, $this->offset);
|
||||
}
|
||||
|
||||
$this->sql = $sql;
|
||||
return !$this->hasError;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply modifier to single value.
|
||||
* @param mixed
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function formatValue($value, $modifier)
|
||||
{
|
||||
// array processing (with or without modifier)
|
||||
if (is_array($value)) {
|
||||
|
||||
$vx = $kx = array();
|
||||
$separator = ', ';
|
||||
switch ($modifier) {
|
||||
case 'and':
|
||||
case 'or':
|
||||
$separator = ' ' . strtoupper($modifier) . ' ';
|
||||
if (!is_string(key($value))) {
|
||||
foreach ($value as $v) {
|
||||
$vx[] = $this->formatValue($v, 'sql');
|
||||
}
|
||||
return implode($separator, $vx);
|
||||
}
|
||||
// break intentionally omitted
|
||||
case 'a': // SET key=val, key=val, ...
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$vx[] = $this->delimite($pair[0]) . '='
|
||||
. $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return implode($separator, $vx);
|
||||
|
||||
|
||||
case 'l': // LIST (val, val, ...)
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return '(' . implode(', ', $vx) . ')';
|
||||
|
||||
|
||||
case 'v': // (key, key, ...) VALUES (val, val, ...)
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$kx[] = $this->delimite($pair[0]);
|
||||
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
|
||||
|
||||
default:
|
||||
foreach ($value as $v) {
|
||||
$vx[] = $this->formatValue($v, $modifier);
|
||||
}
|
||||
return implode(', ', $vx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// with modifier procession
|
||||
if ($modifier) {
|
||||
if ($value === NULL) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
if ($value instanceof IDibiVariable) {
|
||||
return $value->toSql($this, $modifier);
|
||||
}
|
||||
|
||||
if (!is_scalar($value)) { // array is already processed
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected type ' . gettype($value) . '**';
|
||||
}
|
||||
|
||||
switch ($modifier) {
|
||||
case 's': // string
|
||||
case 'bin':// binary
|
||||
case 'b': // boolean
|
||||
return $this->driver->escape($value, $modifier);
|
||||
|
||||
case 'sn': // string or NULL
|
||||
return $value == '' ? 'NULL' : $this->driver->escape($value, dibi::FIELD_TEXT); // notice two equal signs
|
||||
|
||||
case 'i': // signed int
|
||||
case 'u': // unsigned int, ignored
|
||||
// support for numbers - keep them unchanged
|
||||
if (is_string($value) && preg_match('#[+-]?\d+(e\d+)?$#A', $value)) {
|
||||
return $value;
|
||||
}
|
||||
return (string) (int) ($value + 0);
|
||||
|
||||
case 'f': // float
|
||||
// support for numbers - keep them unchanged
|
||||
if (is_numeric($value) && (!is_string($value) || strpos($value, 'x') === FALSE)) {
|
||||
return $value; // something like -9E-005 is accepted by SQL, HEX values is not
|
||||
}
|
||||
return (string) ($value + 0);
|
||||
|
||||
case 'd': // date
|
||||
case 't': // datetime
|
||||
return $this->driver->escape(is_string($value) ? strtotime($value) : $value, $modifier);
|
||||
|
||||
case 'n': // identifier name
|
||||
return $this->delimite($value);
|
||||
|
||||
case 'sql':// preserve as SQL
|
||||
$value = (string) $value;
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($value, '`[\'"');
|
||||
if (strlen($value) === $toSkip) { // needn't be translated
|
||||
return $value;
|
||||
} else {
|
||||
return substr($value, 0, $toSkip)
|
||||
. preg_replace_callback('/(?=`|\[|\'|")(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"(\'|"))/s',
|
||||
array($this, 'cb'),
|
||||
substr($value, $toSkip)
|
||||
);
|
||||
}
|
||||
|
||||
case 'and':
|
||||
case 'or':
|
||||
case 'a':
|
||||
case 'l':
|
||||
case 'v':
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected type ' . gettype($value) . '**';
|
||||
|
||||
default:
|
||||
$this->hasError = TRUE;
|
||||
return "**Unknown or invalid modifier %$modifier**";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// without modifier procession
|
||||
if (is_string($value))
|
||||
return $this->driver->escape($value, dibi::FIELD_TEXT);
|
||||
|
||||
if (is_int($value) || is_float($value))
|
||||
return (string) $value; // something like -9E-005 is accepted by SQL
|
||||
|
||||
if (is_bool($value))
|
||||
return $this->driver->escape($value, dibi::FIELD_BOOL);
|
||||
|
||||
if ($value === NULL)
|
||||
return 'NULL';
|
||||
|
||||
if ($value instanceof IDibiVariable)
|
||||
return $value->toSql($this, NULL);
|
||||
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected ' . gettype($value) . '**';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* PREG callback from translate() or formatValue().
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
private function cb($matches)
|
||||
{
|
||||
// [1] => `ident`
|
||||
// [2] => [ident]
|
||||
// [3] => '
|
||||
// [4] => string
|
||||
// [5] => "
|
||||
// [6] => string
|
||||
// [7] => lone-quote
|
||||
// [8] => modifier (when called from self::translate())
|
||||
|
||||
if (!empty($matches[8])) { // modifier
|
||||
$mod = $matches[8];
|
||||
$cursor = & $this->cursor;
|
||||
|
||||
if ($cursor >= count($this->args) && $mod !== 'else' && $mod !== 'end') {
|
||||
$this->hasError = TRUE;
|
||||
return "**Extra modifier %$mod**";
|
||||
}
|
||||
|
||||
if ($mod === 'if') {
|
||||
$this->ifLevel++;
|
||||
$cursor++;
|
||||
if (!$this->comment && !$this->args[$cursor - 1]) {
|
||||
// open comment
|
||||
$this->ifLevelStart = $this->ifLevel;
|
||||
$this->comment = TRUE;
|
||||
return "/*";
|
||||
}
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'else') {
|
||||
if ($this->ifLevelStart === $this->ifLevel) {
|
||||
$this->ifLevelStart = 0;
|
||||
$this->comment = FALSE;
|
||||
return "*/";
|
||||
} elseif (!$this->comment) {
|
||||
$this->ifLevelStart = $this->ifLevel;
|
||||
$this->comment = TRUE;
|
||||
return "/*";
|
||||
}
|
||||
|
||||
} elseif ($mod === 'end') {
|
||||
$this->ifLevel--;
|
||||
if ($this->ifLevelStart === $this->ifLevel + 1) {
|
||||
// close comment
|
||||
$this->ifLevelStart = 0;
|
||||
$this->comment = FALSE;
|
||||
return "*/";
|
||||
}
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'ex') { // array expansion
|
||||
array_splice($this->args, $cursor, 1, $this->args[$cursor]);
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'lmt') { // apply limit
|
||||
if ($this->args[$cursor] !== NULL) $this->limit = (int) $this->args[$cursor];
|
||||
$cursor++;
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'ofs') { // apply offset
|
||||
if ($this->args[$cursor] !== NULL) $this->offset = (int) $this->args[$cursor];
|
||||
$cursor++;
|
||||
return '';
|
||||
|
||||
} else { // default processing
|
||||
$cursor++;
|
||||
return $this->formatValue($this->args[$cursor - 1], $mod);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->comment) return '...';
|
||||
|
||||
if ($matches[1]) // SQL identifiers: `ident`
|
||||
return $this->delimite($matches[1]);
|
||||
|
||||
if ($matches[2]) // SQL identifiers: [ident]
|
||||
return $this->delimite($matches[2]);
|
||||
|
||||
if ($matches[3]) // SQL strings: '...'
|
||||
return $this->driver->escape( str_replace("''", "'", $matches[4]), dibi::FIELD_TEXT);
|
||||
|
||||
if ($matches[5]) // SQL strings: "..."
|
||||
return $this->driver->escape( str_replace('""', '"', $matches[6]), dibi::FIELD_TEXT);
|
||||
|
||||
if ($matches[7]) { // string quote
|
||||
$this->hasError = TRUE;
|
||||
return '**Alone quote**';
|
||||
}
|
||||
|
||||
die('this should be never executed');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply substitutions to indentifier and delimites it.
|
||||
*
|
||||
* @param string indentifier
|
||||
* @return string
|
||||
*/
|
||||
private function delimite($value)
|
||||
{
|
||||
return $this->driver->escape(dibi::substitute($value), dibi::IDENTIFIER);
|
||||
}
|
||||
|
||||
|
||||
} // class DibiTranslator
|
||||
|
@@ -1,48 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default implemenation of IDibiVariable.
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiVariable extends /*Nette::*/Object implements IDibiVariable
|
||||
{
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
|
||||
/** @var string */
|
||||
public $modifier;
|
||||
|
||||
|
||||
public function __construct($value, $modifier)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->modifier = $modifier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function toSql(DibiTranslator $translator, $modifier)
|
||||
{
|
||||
return $translator->formatValue($this->value, $this->modifier);
|
||||
}
|
||||
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default implemenation of IDibiVariable.
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiVariable extends /*Nette::*/Object implements IDibiVariable
|
||||
{
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
|
||||
/** @var string */
|
||||
public $modifier;
|
||||
|
||||
|
||||
public function __construct($value, $modifier)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->modifier = $modifier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function toSql(DibiTranslator $translator, $modifier)
|
||||
{
|
||||
return $translator->formatValue($this->value, $this->modifier);
|
||||
}
|
||||
|
||||
}
|
@@ -1,256 +1,256 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com/
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com/
|
||||
* @package dibi
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for user variable, used for generating SQL.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDibiVariable
|
||||
{
|
||||
/**
|
||||
* Format for SQL.
|
||||
*
|
||||
* @param object DibiTranslator
|
||||
* @param string optional modifier
|
||||
* @return string SQL code
|
||||
*/
|
||||
function toSql(DibiTranslator $translator, $modifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides an interface between a dataset and data-aware components.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDataSource extends Countable, IteratorAggregate
|
||||
{
|
||||
//function IteratorAggregate::getIterator();
|
||||
//function Countable::count();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi driver interface.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
interface IDibiDriver
|
||||
{
|
||||
|
||||
/**
|
||||
* Internal: Connects to a database.
|
||||
*
|
||||
* @param array
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
function connect(array &$config);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal: Disconnects from a database.
|
||||
*
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
function disconnect();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal: Executes the SQL query.
|
||||
*
|
||||
* @param string SQL statement.
|
||||
* @return IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function query($sql);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
|
||||
*
|
||||
* @return int|FALSE number of rows or FALSE on error
|
||||
*/
|
||||
function affectedRows();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||
*
|
||||
* @return int|FALSE int on success or FALSE on failure
|
||||
*/
|
||||
function insertId($sequence);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function begin();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function commit();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function rollback();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
*
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function escape($value, $type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
*
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function unescape($value, $type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
*
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
function applyLimit(&$sql, $limit, $offset);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function rowCount();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Moves cursor position without fetching row.
|
||||
*
|
||||
* @param int the 0-based cursor pos to seek to
|
||||
* @return boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
function seek($row);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the row at current position and moves the internal cursor to the next position.
|
||||
* internal usage only
|
||||
*
|
||||
* @param bool TRUE for associative array, FALSE for numeric
|
||||
* @return array array on success, nonarray if no next record
|
||||
*/
|
||||
function fetch($type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Frees the resources allocated for this result set.
|
||||
*
|
||||
* @param resource result set resource
|
||||
* @return void
|
||||
*/
|
||||
function free();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a result set.
|
||||
*
|
||||
* @return array
|
||||
* @throws DibiException
|
||||
*/
|
||||
function getColumnsMeta();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getResource();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getResultResource();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a information of the current database.
|
||||
*
|
||||
* @return DibiReflection
|
||||
*/
|
||||
function getDibiReflection();
|
||||
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for user variable, used for generating SQL.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDibiVariable
|
||||
{
|
||||
/**
|
||||
* Format for SQL.
|
||||
*
|
||||
* @param object DibiTranslator
|
||||
* @param string optional modifier
|
||||
* @return string SQL code
|
||||
*/
|
||||
function toSql(DibiTranslator $translator, $modifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides an interface between a dataset and data-aware components.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDataSource extends Countable, IteratorAggregate
|
||||
{
|
||||
//function IteratorAggregate::getIterator();
|
||||
//function Countable::count();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi driver interface.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDibiDriver
|
||||
{
|
||||
|
||||
/**
|
||||
* Internal: Connects to a database.
|
||||
*
|
||||
* @param array
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
function connect(array &$config);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal: Disconnects from a database.
|
||||
*
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
function disconnect();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal: Executes the SQL query.
|
||||
*
|
||||
* @param string SQL statement.
|
||||
* @return IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function query($sql);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
|
||||
*
|
||||
* @return int|FALSE number of rows or FALSE on error
|
||||
*/
|
||||
function affectedRows();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||
*
|
||||
* @return int|FALSE int on success or FALSE on failure
|
||||
*/
|
||||
function insertId($sequence);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function begin();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function commit();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function rollback();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
*
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function escape($value, $type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
*
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function unescape($value, $type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
*
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
function applyLimit(&$sql, $limit, $offset);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function rowCount();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Moves cursor position without fetching row.
|
||||
*
|
||||
* @param int the 0-based cursor pos to seek to
|
||||
* @return boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
function seek($row);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the row at current position and moves the internal cursor to the next position.
|
||||
* internal usage only
|
||||
*
|
||||
* @param bool TRUE for associative array, FALSE for numeric
|
||||
* @return array array on success, nonarray if no next record
|
||||
*/
|
||||
function fetch($type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Frees the resources allocated for this result set.
|
||||
*
|
||||
* @param resource result set resource
|
||||
* @return void
|
||||
*/
|
||||
function free();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a result set.
|
||||
*
|
||||
* @return array
|
||||
* @throws DibiException
|
||||
*/
|
||||
function getColumnsMeta();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getResource();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getResultResource();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a information of the current database.
|
||||
*
|
||||
* @return DibiReflection
|
||||
*/
|
||||
function getDibiReflection();
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user