mirror of
https://github.com/dg/dibi.git
synced 2025-08-16 02:54:25 +02:00
update to 0.5alpha
This commit is contained in:
416
dibi/dibi.php
Normal file
416
dibi/dibi.php
Normal file
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
define('dibi', 'Database Abstraction Layer (c) David Grudl, http://texy.info/dibi/');
|
||||
|
||||
|
||||
if (version_compare(PHP_VERSION , '5.0.3', '<'))
|
||||
die('dibi needs PHP 5.0.3 or newer');
|
||||
|
||||
|
||||
// libraries
|
||||
require_once dirname(__FILE__).'/libs/driver.php';
|
||||
require_once dirname(__FILE__).'/libs/resultset.php';
|
||||
require_once dirname(__FILE__).'/libs/parser.php';
|
||||
require_once dirname(__FILE__).'/libs/exception.php';
|
||||
|
||||
// support
|
||||
require_once dirname(__FILE__).'/libs/date.type.demo.php';
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for user variable, used for generating SQL
|
||||
*/
|
||||
interface IDibiVariable
|
||||
{
|
||||
/**
|
||||
* Format for SQL
|
||||
*
|
||||
* @param object destination DibiDriver
|
||||
* @param string optional modifier
|
||||
* @return string SQL code
|
||||
*/
|
||||
public function toSQL($driver, $modifier = NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for database drivers
|
||||
*
|
||||
* This class is static container class for creating DB objects and
|
||||
* store debug & connections info.
|
||||
*
|
||||
*/
|
||||
class dibi
|
||||
{
|
||||
/**
|
||||
* Connection registry storage for DibiDriver objects
|
||||
* @var array
|
||||
*/
|
||||
static private $registry = array();
|
||||
|
||||
/**
|
||||
* Current connection
|
||||
* @var object DibiDriver
|
||||
*/
|
||||
static private $conn;
|
||||
|
||||
/**
|
||||
* Arguments -> SQL parser
|
||||
* @var object DibiParser
|
||||
*/
|
||||
static private $parser;
|
||||
|
||||
/**
|
||||
* Last SQL command @see dibi::query()
|
||||
* @var string
|
||||
*/
|
||||
static public $sql;
|
||||
static public $error;
|
||||
|
||||
/**
|
||||
* File for logging SQL queryies - strongly recommended to use with NSafeStream
|
||||
* @var string|NULL
|
||||
*/
|
||||
static public $logfile;
|
||||
|
||||
/**
|
||||
* Enable/disable debug mode
|
||||
* @var bool
|
||||
*/
|
||||
static public $debug = false;
|
||||
|
||||
/**
|
||||
* Progressive created query
|
||||
* @var array
|
||||
*/
|
||||
static private $query = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new DibiDriver object and connects it to specified database
|
||||
*
|
||||
* @param array connection parameters
|
||||
* @param string connection name
|
||||
* @return bool|object TRUE on success, FALSE or Exception on failure
|
||||
*/
|
||||
static public function connect($config, $name = 'def')
|
||||
{
|
||||
// init parser
|
||||
if (!self::$parser) self::$parser = new DibiParser();
|
||||
|
||||
// $name must be unique
|
||||
if (isset(self::$registry[$name]))
|
||||
return new DibiException("Connection named '$name' already exists.");
|
||||
|
||||
// config['driver'] is required
|
||||
if (empty($config['driver']))
|
||||
return new DibiException('Driver is not specified.');
|
||||
|
||||
// include dibi driver
|
||||
$className = "Dibi$config[driver]Driver";
|
||||
require_once dirname(__FILE__) . "/drivers/$config[driver].php";
|
||||
|
||||
if (!class_exists($className))
|
||||
return new DibiException("Unable to create instance of dibi driver class '$className'.");
|
||||
|
||||
|
||||
// create connection object
|
||||
/** like $conn = $className::connect($config); */
|
||||
$conn = call_user_func(array($className, 'connect'), $config);
|
||||
|
||||
// optionally log to file
|
||||
// todo: log other exceptions!
|
||||
if (self::$logfile != NULL) {
|
||||
if (is_error($conn))
|
||||
$msg = "Can't connect to DB '$config[driver]': ".$conn->getMessage();
|
||||
else
|
||||
$msg = "Successfully connected to DB '$config[driver]'";
|
||||
|
||||
$f = fopen(self::$logfile, 'a');
|
||||
fwrite($f, "$msg\r\n\r\n");
|
||||
fclose($f);
|
||||
}
|
||||
|
||||
if (is_error($conn)) {
|
||||
// optionally debug on display
|
||||
if (self::$debug) echo '[dibi error] ' . $conn->getMessage();
|
||||
|
||||
return $conn; // reraise the exception
|
||||
}
|
||||
|
||||
// store connection in list
|
||||
self::$conn = self::$registry[$name] = $conn;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns TRUE when connection was established
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static public function isConnected()
|
||||
{
|
||||
return (bool) self::$conn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve active connection
|
||||
*
|
||||
* @param string connection registy name or NULL for active connection
|
||||
* @return object DibiDriver object.
|
||||
*/
|
||||
static public function getConnection($name = NULL)
|
||||
{
|
||||
return $name === NULL
|
||||
? self::$conn
|
||||
: @self::$registry[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change active connection
|
||||
*
|
||||
* @param string connection registy name
|
||||
* @return void
|
||||
*/
|
||||
static public function activate($name)
|
||||
{
|
||||
if (!isset(self::$registry[$name]))
|
||||
return FALSE;
|
||||
|
||||
// change active connection
|
||||
self::$conn = self::$registry[$name];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and executes SQL query
|
||||
*
|
||||
* @param mixed one or more arguments
|
||||
* @return int|DibiResult|Exception
|
||||
*/
|
||||
static public function query()
|
||||
{
|
||||
if (!self::$conn) return new DibiException('Dibi is not connected to DB'); // is connected?
|
||||
|
||||
// receive arguments
|
||||
$args = func_num_args() ? func_get_args() : self::$query;
|
||||
self::$query = array();
|
||||
|
||||
// and generate SQL
|
||||
self::$sql = self::$parser->parse(self::$conn, $args);
|
||||
if (is_error(self::$sql)) return self::$sql; // reraise the exception
|
||||
|
||||
// execute SQL
|
||||
$timer = -microtime(true);
|
||||
$res = self::$conn->query(self::$sql);
|
||||
$timer += microtime(true);
|
||||
|
||||
if (is_error($res)) {
|
||||
// optionally debug on display
|
||||
if (self::$debug) {
|
||||
echo '[dibi error] ' . $res->getMessage();
|
||||
self::dump(self::$sql);
|
||||
}
|
||||
// todo: log all errors!
|
||||
self::$error = $res;
|
||||
} else {
|
||||
self::$error = FALSE;
|
||||
}
|
||||
|
||||
// optionally log to file
|
||||
if (self::$logfile != NULL)
|
||||
{
|
||||
if (is_error($res))
|
||||
$msg = $res->getMessage();
|
||||
elseif ($res instanceof DibiResult)
|
||||
$msg = 'object('.get_class($res).') rows: '.$res->rowCount();
|
||||
else
|
||||
$msg = 'OK';
|
||||
|
||||
$f = fopen(self::$logfile, 'a');
|
||||
fwrite($f,
|
||||
self::$sql
|
||||
. ";\r\n-- Result: $msg"
|
||||
. "\r\n-- Takes: " . sprintf('%0.3f', $timer * 1000) . ' ms'
|
||||
. "\r\n\r\n"
|
||||
);
|
||||
fclose($f);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
static public function queryStart()
|
||||
{
|
||||
self::$query = func_get_args();
|
||||
}
|
||||
|
||||
|
||||
static public function queryAdd()
|
||||
{
|
||||
$args = func_get_args();
|
||||
self::$query = array_merge(self::$query, $args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and returns SQL query
|
||||
*
|
||||
* @param mixed one or more arguments
|
||||
* @return string
|
||||
*/
|
||||
static public function test()
|
||||
{
|
||||
if (!self::$conn) return FALSE; // is connected?
|
||||
|
||||
// receive arguments
|
||||
$args = func_num_args() ? func_get_args() : self::$query;
|
||||
self::$query = array();
|
||||
|
||||
// and generate SQL
|
||||
$sql = self::$parser->parse(self::$conn, $args);
|
||||
if (is_error($sql)) {
|
||||
self::dump($sql->getSql());
|
||||
return $sql->getSql();
|
||||
} else {
|
||||
self::dump($sql);
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Monostate for DibiDriver::insertId()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
static public function insertId()
|
||||
{
|
||||
if (!self::$conn) return FALSE; // is connected?
|
||||
|
||||
return self::$conn->insertId();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Monostate for DibiDriver::affectedRows()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
static public function affectedRows()
|
||||
{
|
||||
if (!self::$conn) return FALSE; // is connected?
|
||||
|
||||
return self::$conn->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prints out a syntax highlighted version of the SQL command
|
||||
*
|
||||
* @param string SQL command
|
||||
* @return void
|
||||
*/
|
||||
static public function dump($sql) {
|
||||
static $highlight = array ('ALL', 'DISTINCT', 'AS', 'ON', 'INTO', 'AND', 'OR', 'AS', );
|
||||
static $newline = array ('SELECT', 'UPDATE', 'INSERT', 'DELETE', 'FROM', 'WHERE', 'HAVING', 'GROUP BY', 'ORDER BY', 'LIMIT', 'SET', 'VALUES', 'LEFT JOIN', 'INNER JOIN',);
|
||||
|
||||
// insert new lines
|
||||
foreach ($newline as $word)
|
||||
$sql = preg_replace('#\b'.$word.'\b#', "\n\$0", $sql);
|
||||
|
||||
$sql = trim($sql);
|
||||
// reduce spaces
|
||||
// $sql = preg_replace('# +#', ' ', $sql);
|
||||
|
||||
$sql = wordwrap($sql, 100);
|
||||
$sql = htmlSpecialChars($sql);
|
||||
$sql = strtr($sql, array("\n" => '<br />'));
|
||||
|
||||
foreach ($newline as $word)
|
||||
$sql = preg_replace('#\b'.$word.'\b#', '<strong style="color:blue">$0</strong>', $sql);
|
||||
|
||||
foreach ($highlight as $word)
|
||||
$sql = preg_replace('#\b'.$word.'\b#', '<strong style="color:green">$0</strong>', $sql);
|
||||
|
||||
$sql = preg_replace('#\*\*.+?\*\*#', '<strong style="color:red">$0</strong>', $sql);
|
||||
|
||||
echo '<pre>', $sql, '</pre>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Displays complete result-set as HTML table
|
||||
*
|
||||
* @param object DibiResult
|
||||
* @return void
|
||||
*/
|
||||
static public function dumpResult(DibiResult $res)
|
||||
{
|
||||
echo '<table class="dump"><tr>';
|
||||
echo '<th>Row</th>';
|
||||
$fieldCount = $res->fieldCount();
|
||||
for ($i = 0; $i < $fieldCount; $i++) {
|
||||
$info = $res->fieldMeta($i);
|
||||
echo '<th>'.htmlSpecialChars($info['name']).'</th>';
|
||||
}
|
||||
echo '</tr>';
|
||||
|
||||
foreach ($res as $row => $fields) {
|
||||
echo '<tr><th>', $row, '</th>';
|
||||
foreach ($fields as $field) {
|
||||
if (is_object($field)) $field = $field->__toString();
|
||||
echo '<td>', htmlSpecialChars($field), '</td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</table>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // class dibi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
334
dibi/drivers/mysql.php
Normal file
334
dibi/drivers/mysql.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for MySQL database
|
||||
*
|
||||
*/
|
||||
class DibiMySqlDriver extends DibiDriver {
|
||||
private
|
||||
$conn;
|
||||
|
||||
public
|
||||
$formats = array(
|
||||
'NULL' => "NULL",
|
||||
'TRUE' => "1",
|
||||
'FALSE' => "0",
|
||||
'date' => "'Y-m-d'",
|
||||
'datetime' => "'Y-m-d H:i:s'",
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Driver factory
|
||||
*/
|
||||
public static function connect($config)
|
||||
{
|
||||
if (!extension_loaded('mysql'))
|
||||
return new DibiException("PHP extension 'mysql' is not loaded");
|
||||
|
||||
|
||||
if (empty($config['host'])) $config['host'] = 'localhost';
|
||||
|
||||
if (@$config['protocol'] === 'unix') // host can be socket
|
||||
$host = ':' . $config['host'];
|
||||
else
|
||||
$host = $config['host'] . (empty($config['port']) ? '' : $config['port']);
|
||||
|
||||
|
||||
// some errors aren't handled. Must use $php_errormsg
|
||||
if (function_exists('ini_set'))
|
||||
$save = ini_set('track_errors', TRUE);
|
||||
$php_errormsg = '';
|
||||
|
||||
if (empty($config['persistent']))
|
||||
$conn = @mysql_connect($host, @$config['username'], @$config['password']);
|
||||
else
|
||||
$conn = @mysql_pconnect($host, @$config['username'], @$config['password']);
|
||||
|
||||
if (function_exists('ini_set'))
|
||||
ini_set('track_errors', $save);
|
||||
|
||||
|
||||
if (!is_resource($conn))
|
||||
return new DibiException("Connecting error", array(
|
||||
'message' => mysql_error() ? mysql_error() : $php_errormsg,
|
||||
'code' => mysql_errno(),
|
||||
));
|
||||
|
||||
|
||||
if (!empty($config['charset'])) {
|
||||
$succ = @mysql_query('SET CHARACTER SET '.$config['charset'], $conn);
|
||||
// don't handle this error...
|
||||
}
|
||||
|
||||
|
||||
if (!empty($config['database'])) {
|
||||
if (!@mysql_select_db($config['database'], $conn))
|
||||
return new DibiException("Connecting error", array(
|
||||
'message' => mysql_error($conn),
|
||||
'code' => mysql_errno($conn),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$obj = new self($config);
|
||||
$obj->conn = $conn;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function query($sql)
|
||||
{
|
||||
$res = @mysql_query($sql, $this->conn);
|
||||
|
||||
if (is_resource($res))
|
||||
return new DibiMySqlResult($res);
|
||||
|
||||
if ($res === FALSE)
|
||||
return new DibiException("Query error", array(
|
||||
'message' => mysql_error($this->conn),
|
||||
'code' => mysql_errno($this->conn),
|
||||
'sql' => $sql,
|
||||
));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = mysql_affected_rows($this->conn);
|
||||
return $rows < 0 ? FALSE : $rows;
|
||||
}
|
||||
|
||||
|
||||
public function insertId()
|
||||
{
|
||||
$id = mysql_insert_id($this->conn);
|
||||
return $id < 0 ? FALSE : $id;
|
||||
}
|
||||
|
||||
|
||||
public function begin()
|
||||
{
|
||||
return mysql_query('BEGIN', $this->conn);
|
||||
}
|
||||
|
||||
|
||||
public function commit()
|
||||
{
|
||||
return mysql_query('COMMIT', $this->conn);
|
||||
}
|
||||
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
return mysql_query('ROLLBACK', $this->conn);
|
||||
}
|
||||
|
||||
|
||||
public function escape($value, $appendQuotes = FALSE)
|
||||
{
|
||||
return $appendQuotes
|
||||
? "'" . mysql_real_escape_string($value, $this->conn) . "'"
|
||||
: mysql_real_escape_string($value, $this->conn);
|
||||
}
|
||||
|
||||
|
||||
public function quoteName($value)
|
||||
{
|
||||
return '`' . strtr($value, array('.' => '`.`')) . '`';
|
||||
}
|
||||
|
||||
|
||||
public function getMetaData()
|
||||
{
|
||||
trigger_error('Meta is not implemented yet.', E_USER_WARNING);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// is this really needed?
|
||||
public function getResource()
|
||||
{
|
||||
return $this->conn;
|
||||
}
|
||||
|
||||
// experimental
|
||||
public function applyLimit(&$sql, $offset, $limit)
|
||||
{
|
||||
if ($limit > 0) {
|
||||
$sql .= " LIMIT " . (int) $limit . ($offset > 0 ? " OFFSET " . (int) $offset : "");
|
||||
} elseif ($offset > 0) {
|
||||
$sql .= " LIMIT " . $offset . ", 18446744073709551615";
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
} // DibiMySqlDriver
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DibiMySqlResult extends DibiResult
|
||||
{
|
||||
private
|
||||
$resource,
|
||||
$meta;
|
||||
|
||||
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
|
||||
public function rowCount()
|
||||
{
|
||||
return mysql_num_rows($this->resource);
|
||||
}
|
||||
|
||||
|
||||
protected function doFetch()
|
||||
{
|
||||
return mysql_fetch_assoc($this->resource);
|
||||
}
|
||||
|
||||
|
||||
public function seek($row)
|
||||
{
|
||||
return mysql_data_seek($this->resource, $row);
|
||||
}
|
||||
|
||||
|
||||
protected function free()
|
||||
{
|
||||
mysql_free_result($this->resource);
|
||||
}
|
||||
|
||||
|
||||
public function getFields()
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return array_keys($this->meta);
|
||||
}
|
||||
|
||||
|
||||
protected function detectTypes()
|
||||
{
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
}
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
public function getMetaData($field)
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return isset($this->meta[$field]) ? $this->meta[$field] : FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
private function createMeta()
|
||||
{
|
||||
static $types = array(
|
||||
'ENUM' => self::FIELD_TEXT, // eventually self::FIELD_INTEGER
|
||||
'SET' => self::FIELD_TEXT, // eventually self::FIELD_INTEGER
|
||||
'CHAR' => self::FIELD_TEXT,
|
||||
'VARCHAR' => self::FIELD_TEXT,
|
||||
'STRING' => self::FIELD_TEXT,
|
||||
'TINYTEXT' => self::FIELD_TEXT,
|
||||
'TEXT' => self::FIELD_TEXT,
|
||||
'MEDIUMTEXT'=> self::FIELD_TEXT,
|
||||
'LONGTEXT' => self::FIELD_TEXT,
|
||||
'BINARY' => self::FIELD_BINARY,
|
||||
'VARBINARY' => self::FIELD_BINARY,
|
||||
'TINYBLOB' => self::FIELD_BINARY,
|
||||
'BLOB' => self::FIELD_BINARY,
|
||||
'MEDIUMBLOB'=> self::FIELD_BINARY,
|
||||
'LONGBLOB' => self::FIELD_BINARY,
|
||||
'DATE' => self::FIELD_DATE,
|
||||
'DATETIME' => self::FIELD_DATETIME,
|
||||
'TIMESTAMP' => self::FIELD_DATETIME,
|
||||
'TIME' => self::FIELD_DATETIME,
|
||||
'BIT' => self::FIELD_BOOL,
|
||||
'YEAR' => self::FIELD_INTEGER,
|
||||
'TINYINT' => self::FIELD_INTEGER,
|
||||
'SMALLINT' => self::FIELD_INTEGER,
|
||||
'MEDIUMINT' => self::FIELD_INTEGER,
|
||||
'INT' => self::FIELD_INTEGER,
|
||||
'INTEGER' => self::FIELD_INTEGER,
|
||||
'BIGINT' => self::FIELD_INTEGER,
|
||||
'FLOAT' => self::FIELD_FLOAT,
|
||||
'DOUBLE' => self::FIELD_FLOAT,
|
||||
'REAL' => self::FIELD_FLOAT,
|
||||
'DECIMAL' => self::FIELD_FLOAT,
|
||||
'NUMERIC' => self::FIELD_FLOAT,
|
||||
);
|
||||
|
||||
$count = mysql_num_fields($this->resource);
|
||||
$this->meta = $this->convert = array();
|
||||
for ($index = 0; $index < $count; $index++) {
|
||||
|
||||
$info['native'] = $native = strtoupper(mysql_field_type($this->resource, $index));
|
||||
$info['flags'] = explode(' ', mysql_field_flags($this->resource, $index));
|
||||
$info['length'] = mysql_field_len($this->resource, $index);
|
||||
$info['table'] = mysql_field_table($this->resource, $index);
|
||||
|
||||
if (in_array('auto_increment', $info['flags'])) // or 'primary_key' ?
|
||||
$info['type'] = self::FIELD_COUNTER;
|
||||
else {
|
||||
$info['type'] = isset($types[$native]) ? $types[$native] : self::FIELD_UNKNOWN;
|
||||
|
||||
// if ($info['type'] == self::FIELD_TEXT && $info['length'] > 255)
|
||||
// $info['type'] = self::FIELD_LONG_TEXT;
|
||||
}
|
||||
|
||||
$name = mysql_field_name($this->resource, $index);
|
||||
$this->meta[$name] = $info;
|
||||
$this->convert[$name] = $info['type'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // class DibiMySqlResult
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
282
dibi/drivers/mysqli.php
Normal file
282
dibi/drivers/mysqli.php
Normal file
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for MySQLi database
|
||||
*
|
||||
*/
|
||||
class DibiMySqliDriver extends DibiDriver {
|
||||
private
|
||||
$conn;
|
||||
|
||||
public
|
||||
$formats = array(
|
||||
'NULL' => "NULL",
|
||||
'TRUE' => "1",
|
||||
'FALSE' => "0",
|
||||
'date' => "'Y-m-d'",
|
||||
'datetime' => "'Y-m-d H:i:s'",
|
||||
);
|
||||
|
||||
|
||||
|
||||
public static function connect($config)
|
||||
{
|
||||
if (!extension_loaded('mysqli'))
|
||||
return new DibiException("PHP extension 'mysqli' is not loaded");
|
||||
|
||||
if (empty($config['host'])) $config['host'] = 'localhost';
|
||||
|
||||
$conn = @mysqli_connect($config['host'], @$config['username'], @$config['password'], @$config['database'], @$config['port']);
|
||||
|
||||
if (!$conn)
|
||||
return new DibiException("Connecting error", array(
|
||||
'message' => mysqli_connect_error(),
|
||||
'code' => mysqli_connect_errno(),
|
||||
));
|
||||
|
||||
if (!empty($config['charset']))
|
||||
mysqli_query($conn, 'SET CHARACTER SET '.$config['charset']);
|
||||
|
||||
$obj = new self($config);
|
||||
$obj->conn = $conn;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function query($sql)
|
||||
{
|
||||
$res = @mysqli_query($this->conn, $sql);
|
||||
|
||||
if (is_object($res))
|
||||
return new DibiMySqliResult($res);
|
||||
|
||||
if ($res === FALSE)
|
||||
return new DibiException("Query error", $this->errorInfo($sql));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = mysqli_affected_rows($this->conn);
|
||||
return $rows < 0 ? FALSE : $rows;
|
||||
}
|
||||
|
||||
|
||||
public function insertId()
|
||||
{
|
||||
$id = mysqli_insert_id($this->conn);
|
||||
return $id < 1 ? FALSE : $id;
|
||||
}
|
||||
|
||||
|
||||
public function begin()
|
||||
{
|
||||
return mysqli_autocommit($this->conn, FALSE);
|
||||
}
|
||||
|
||||
|
||||
public function commit()
|
||||
{
|
||||
$ok = mysqli_commit($this->conn);
|
||||
mysqli_autocommit($this->conn, TRUE);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
$ok = mysqli_rollback($this->conn);
|
||||
mysqli_autocommit($this->conn, TRUE);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
private function errorInfo($sql = NULL)
|
||||
{
|
||||
return array(
|
||||
'message' => mysqli_error($this->conn),
|
||||
'code' => mysqli_errno($this->conn),
|
||||
'sql' => $sql,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function escape($value, $appendQuotes = FALSE)
|
||||
{
|
||||
return $appendQuotes
|
||||
? "'" . mysqli_real_escape_string($this->conn, $value) . "'"
|
||||
: mysqli_real_escape_string($this->conn, $value);
|
||||
}
|
||||
|
||||
|
||||
public function quoteName($value)
|
||||
{
|
||||
return '`' . strtr($value, array('.' => '`.`')) . '`';
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getMetaData()
|
||||
{
|
||||
trigger_error('Meta is not implemented yet.', E_USER_WARNING);
|
||||
}
|
||||
|
||||
|
||||
} // class DibiMySqliDriver
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DibiMySqliResult extends DibiResult
|
||||
{
|
||||
private
|
||||
$resource,
|
||||
$meta;
|
||||
|
||||
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
|
||||
public function rowCount()
|
||||
{
|
||||
return mysqli_num_rows($this->resource);
|
||||
}
|
||||
|
||||
|
||||
protected function doFetch()
|
||||
{
|
||||
return mysqli_fetch_assoc($this->resource);
|
||||
}
|
||||
|
||||
|
||||
public function seek($row)
|
||||
{
|
||||
return mysqli_data_seek($this->resource, $row);
|
||||
}
|
||||
|
||||
|
||||
protected function free()
|
||||
{
|
||||
mysqli_free_result($this->resource);
|
||||
}
|
||||
|
||||
|
||||
public function getFields()
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return array_keys($this->meta);
|
||||
}
|
||||
|
||||
|
||||
protected function detectTypes()
|
||||
{
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
}
|
||||
|
||||
/** this is experimental */
|
||||
public function getMetaData($field)
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return isset($this->meta[$field]) ? $this->meta[$field] : FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
private function createMeta()
|
||||
{
|
||||
static $types = array(
|
||||
MYSQLI_TYPE_FLOAT => self::FIELD_FLOAT,
|
||||
MYSQLI_TYPE_DOUBLE => self::FIELD_FLOAT,
|
||||
MYSQLI_TYPE_DECIMAL => self::FIELD_FLOAT,
|
||||
// MYSQLI_TYPE_NEWDECIMAL=> self::FIELD_FLOAT,
|
||||
// MYSQLI_TYPE_BIT => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_TINY => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_SHORT => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_LONG => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_LONGLONG => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_INT24 => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_YEAR => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_GEOMETRY => self::FIELD_INTEGER,
|
||||
MYSQLI_TYPE_DATE => self::FIELD_DATE,
|
||||
MYSQLI_TYPE_NEWDATE => self::FIELD_DATE,
|
||||
MYSQLI_TYPE_TIMESTAMP => self::FIELD_DATETIME,
|
||||
MYSQLI_TYPE_TIME => self::FIELD_DATETIME,
|
||||
MYSQLI_TYPE_DATETIME => self::FIELD_DATETIME,
|
||||
MYSQLI_TYPE_ENUM => self::FIELD_TEXT, // eventually self::FIELD_INTEGER
|
||||
MYSQLI_TYPE_SET => self::FIELD_TEXT, // eventually self::FIELD_INTEGER
|
||||
MYSQLI_TYPE_STRING => self::FIELD_TEXT,
|
||||
MYSQLI_TYPE_VAR_STRING=> self::FIELD_TEXT,
|
||||
MYSQLI_TYPE_TINY_BLOB => self::FIELD_BINARY,
|
||||
MYSQLI_TYPE_MEDIUM_BLOB=> self::FIELD_BINARY,
|
||||
MYSQLI_TYPE_LONG_BLOB => self::FIELD_BINARY,
|
||||
MYSQLI_TYPE_BLOB => self::FIELD_BINARY,
|
||||
);
|
||||
|
||||
$count = mysqli_num_fields($this->resource);
|
||||
$this->meta = $this->convert = array();
|
||||
for ($index = 0; $index < $count; $index++) {
|
||||
$info = (array) mysqli_fetch_field_direct($this->resource, $index);
|
||||
$native = $info['native'] = $info['type'];
|
||||
|
||||
if ($info['flags'] & MYSQLI_AUTO_INCREMENT_FLAG) // or 'primary_key' ?
|
||||
$info['type'] = self::FIELD_COUNTER;
|
||||
else {
|
||||
$info['type'] = isset($types[$native]) ? $types[$native] : self::FIELD_UNKNOWN;
|
||||
// if ($info['type'] == self::FIELD_TEXT && $info['length'] > 255)
|
||||
// $info['type'] = self::FIELD_LONG_TEXT;
|
||||
}
|
||||
|
||||
$this->meta[$info['name']] = $info;
|
||||
$this->convert[$info['name']] = $info['type'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // class DibiMySqliResult
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
273
dibi/drivers/odbc.php
Normal file
273
dibi/drivers/odbc.php
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver interacting with databases via ODBC connections
|
||||
*
|
||||
*/
|
||||
class DibiOdbcDriver extends DibiDriver {
|
||||
private
|
||||
$conn;
|
||||
|
||||
public
|
||||
$formats = array(
|
||||
'NULL' => "NULL",
|
||||
'TRUE' => "-1",
|
||||
'FALSE' => "0",
|
||||
'date' => "#m/d/Y#",
|
||||
'datetime' => "#m/d/Y H:i:s#",
|
||||
);
|
||||
|
||||
|
||||
|
||||
public static function connect($config)
|
||||
{
|
||||
if (!extension_loaded('odbc'))
|
||||
return new DibiException("PHP extension 'odbc' is not loaded");
|
||||
|
||||
if (@$config['persistent'])
|
||||
$conn = @odbc_pconnect($config['database'], $config['username'], $config['password']);
|
||||
else
|
||||
$conn = @odbc_connect($config['database'], $config['username'], $config['password']);
|
||||
|
||||
if (!is_resource($conn))
|
||||
return new DibiException("Connecting error", array(
|
||||
'message' => odbc_errormsg(),
|
||||
'code' => odbc_error(),
|
||||
));
|
||||
|
||||
$obj = new self($config);
|
||||
$obj->conn = $conn;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function query($sql)
|
||||
{
|
||||
$res = @odbc_exec($this->conn, $sql);
|
||||
|
||||
if (is_resource($res))
|
||||
return new DibiOdbcResult($res);
|
||||
|
||||
if ($res === FALSE)
|
||||
return new DibiException("Query error", $this->errorInfo($sql));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = odbc_num_rows($this->conn);
|
||||
return $rows < 0 ? FALSE : $rows;
|
||||
}
|
||||
|
||||
|
||||
public function insertId()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
public function begin()
|
||||
{
|
||||
return odbc_autocommit($this->conn, FALSE);
|
||||
}
|
||||
|
||||
|
||||
public function commit()
|
||||
{
|
||||
$ok = odbc_commit($this->conn);
|
||||
odbc_autocommit($this->conn, TRUE);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
$ok = odbc_rollback($this->conn);
|
||||
odbc_autocommit($this->conn, TRUE);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
private function errorInfo($sql = NULL)
|
||||
{
|
||||
return array(
|
||||
'message' => odbc_errormsg($this->conn),
|
||||
'code' => odbc_error($this->conn),
|
||||
'sql' => $sql,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function escape($value, $appendQuotes = FALSE)
|
||||
{
|
||||
$value = str_replace("'", "''", $value);
|
||||
return $appendQuotes
|
||||
? "'" . $value . "'"
|
||||
: $value;
|
||||
}
|
||||
|
||||
|
||||
public function quoteName($value)
|
||||
{
|
||||
return '[' . strtr($value, array('.' => '].[')) . ']';
|
||||
}
|
||||
|
||||
|
||||
public function getMetaData()
|
||||
{
|
||||
trigger_error('Meta is not implemented yet.', E_USER_WARNING);
|
||||
}
|
||||
|
||||
} // class DibiOdbcDriver
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DibiOdbcResult extends DibiResult
|
||||
{
|
||||
private
|
||||
$resource,
|
||||
$meta,
|
||||
$row = 0;
|
||||
|
||||
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
|
||||
public function rowCount()
|
||||
{
|
||||
// will return -1 with many drivers :-(
|
||||
return odbc_num_rows($this->resource);
|
||||
}
|
||||
|
||||
|
||||
protected function doFetch()
|
||||
{
|
||||
return odbc_fetch_array($this->resource, $this->row++);
|
||||
}
|
||||
|
||||
|
||||
public function seek($row)
|
||||
{
|
||||
$this->row = $row;
|
||||
}
|
||||
|
||||
|
||||
protected function free()
|
||||
{
|
||||
odbc_free_result($this->resource);
|
||||
}
|
||||
|
||||
|
||||
public function getFields()
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return array_keys($this->meta);
|
||||
}
|
||||
|
||||
|
||||
protected function detectTypes()
|
||||
{
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
}
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
public function getMetaData($field)
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return isset($this->meta[$field]) ? $this->meta[$field] : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
private function createMeta()
|
||||
{
|
||||
// cache
|
||||
if ($this->meta !== NULL)
|
||||
return $this->meta;
|
||||
|
||||
static $types = array(
|
||||
'CHAR' => self::FIELD_TEXT,
|
||||
'COUNTER' => self::FIELD_COUNTER,
|
||||
'VARCHAR' => self::FIELD_TEXT,
|
||||
'LONGCHAR' => self::FIELD_TEXT,
|
||||
'INTEGER' => self::FIELD_INTEGER,
|
||||
'DATETIME' => self::FIELD_DATETIME,
|
||||
'CURRENCY' => self::FIELD_FLOAT,
|
||||
'BIT' => self::FIELD_BOOL,
|
||||
'LONGBINARY'=> self::FIELD_BINARY,
|
||||
'SMALLINT' => self::FIELD_INTEGER,
|
||||
'BYTE' => self::FIELD_INTEGER,
|
||||
'BIGINT' => self::FIELD_INTEGER,
|
||||
'INT' => self::FIELD_INTEGER,
|
||||
'TINYINT' => self::FIELD_INTEGER,
|
||||
'REAL' => self::FIELD_FLOAT,
|
||||
'DOUBLE' => self::FIELD_FLOAT,
|
||||
'DECIMAL' => self::FIELD_FLOAT,
|
||||
'NUMERIC' => self::FIELD_FLOAT,
|
||||
'MONEY' => self::FIELD_FLOAT,
|
||||
'SMALLMONEY'=> self::FIELD_FLOAT,
|
||||
'FLOAT' => self::FIELD_FLOAT,
|
||||
'YESNO' => self::FIELD_BOOL,
|
||||
// and many others?
|
||||
);
|
||||
|
||||
$count = odbc_num_fields($this->resource);
|
||||
$this->meta = $this->convert = array();
|
||||
for ($index = 1; $index <= $count; $index++) {
|
||||
$native = strtoupper(odbc_field_type($this->resource, $index));
|
||||
$name = odbc_field_name($this->resource, $index);
|
||||
$this->meta[$name] = array(
|
||||
'type' => isset($types[$native]) ? $types[$native] : self::FIELD_UNKNOWN,
|
||||
'native' => $native,
|
||||
'length' => odbc_field_len($this->resource, $index),
|
||||
'scale' => odbc_field_scale($this->resource, $index),
|
||||
'precision' => odbc_field_precision($this->resource, $index),
|
||||
);
|
||||
$this->convert[$name] = $this->meta[$name]['type'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // class DibiOdbcResult
|
||||
|
||||
|
||||
?>
|
0
dibi/drivers/postgresql.php
Normal file
0
dibi/drivers/postgresql.php
Normal file
233
dibi/drivers/sqlite.php
Normal file
233
dibi/drivers/sqlite.php
Normal file
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for SQlite database
|
||||
*
|
||||
*/
|
||||
class DibiSqliteDriver extends DibiDriver {
|
||||
private
|
||||
$conn;
|
||||
|
||||
public
|
||||
$formats = array(
|
||||
'NULL' => "NULL",
|
||||
'TRUE' => "1",
|
||||
'FALSE' => "0",
|
||||
'date' => "'Y-m-d'",
|
||||
'datetime' => "'Y-m-d H:i:s'",
|
||||
);
|
||||
|
||||
|
||||
|
||||
public static function connect($config)
|
||||
{
|
||||
if (!extension_loaded('sqlite'))
|
||||
return new DibiException("PHP extension 'sqlite' is not loaded");
|
||||
|
||||
if (empty($config['database']))
|
||||
return new DibiException("Database must be specified");
|
||||
|
||||
$errorMsg = '';
|
||||
if (empty($config['persistent']))
|
||||
$conn = @sqlite_open($config['database'], @$config['mode'], $errorMsg);
|
||||
else
|
||||
$conn = @sqlite_popen($config['database'], @$config['mode'], $errorMsg);
|
||||
|
||||
if (!$conn)
|
||||
return new DibiException("Connecting error", array(
|
||||
'message' => $errorMsg,
|
||||
));
|
||||
|
||||
$obj = new self($config);
|
||||
$obj->conn = $conn;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function query($sql)
|
||||
{
|
||||
$errorMsg = '';
|
||||
$res = @sqlite_query($this->conn, $sql, SQLITE_ASSOC, $errorMsg);
|
||||
|
||||
if ($res === FALSE)
|
||||
return new DibiException("Query error", array(
|
||||
'message' => $errorMsg,
|
||||
'sql' => $sql,
|
||||
));
|
||||
|
||||
if (is_resource($res))
|
||||
return new DibiSqliteResult($res);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = sqlite_changes($this->conn);
|
||||
return $rows < 0 ? FALSE : $rows;
|
||||
}
|
||||
|
||||
|
||||
public function insertId()
|
||||
{
|
||||
$id = sqlite_last_insert_rowid($this->conn);
|
||||
return $id < 1 ? FALSE : $id;
|
||||
}
|
||||
|
||||
|
||||
public function begin()
|
||||
{
|
||||
return sqlite_query($this->conn, 'BEGIN');
|
||||
}
|
||||
|
||||
|
||||
public function commit()
|
||||
{
|
||||
return sqlite_query($this->conn, 'COMMIT');
|
||||
}
|
||||
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
return sqlite_query($this->conn, 'ROLLBACK');
|
||||
}
|
||||
|
||||
|
||||
public function escape($value, $appendQuotes = FALSE)
|
||||
{
|
||||
return $appendQuotes
|
||||
? "'" . sqlite_escape_string($value) . "'"
|
||||
: sqlite_escape_string($value);
|
||||
}
|
||||
|
||||
|
||||
public function quoteName($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getMetaData()
|
||||
{
|
||||
trigger_error('Meta is not implemented yet.', E_USER_WARNING);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // class DibiSqliteDriver
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DibiSqliteResult extends DibiResult
|
||||
{
|
||||
private
|
||||
$resource,
|
||||
$meta;
|
||||
|
||||
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
|
||||
public function rowCount()
|
||||
{
|
||||
return sqlite_num_rows($this->resource);
|
||||
}
|
||||
|
||||
|
||||
protected function doFetch()
|
||||
{
|
||||
return sqlite_fetch_array($this->resource, SQLITE_ASSOC);
|
||||
}
|
||||
|
||||
|
||||
public function seek($row)
|
||||
{
|
||||
return sqlite_seek($this->resource, $row);
|
||||
}
|
||||
|
||||
|
||||
protected function free()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function getFields()
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return array_keys($this->meta);
|
||||
}
|
||||
|
||||
|
||||
protected function detectTypes()
|
||||
{
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
}
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
public function getMetaData($field)
|
||||
{
|
||||
// cache
|
||||
if ($this->meta === NULL)
|
||||
$this->createMeta();
|
||||
|
||||
return isset($this->meta[$field]) ? $this->meta[$field] : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/** this is experimental */
|
||||
private function createMeta()
|
||||
{
|
||||
$count = sqlite_num_fields($this->resource);
|
||||
$this->meta = $this->convert = array();
|
||||
for ($index = 0; $index < $count; $index++) {
|
||||
$name = sqlite_field_name($this->resource, $index);
|
||||
$this->meta[$name] = array('type' => self::FIELD_UNKNOWN);
|
||||
$this->convert[$name] = self::FIELD_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // class DibiSqliteResult
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
101
dibi/libs/date.type.demo.php
Normal file
101
dibi/libs/date.type.demo.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
// required since PHP 5.1.0
|
||||
// todo:
|
||||
if (function_exists('date_default_timezone_set'))
|
||||
date_default_timezone_set('Europe/Prague'); // or 'GMT'
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pseudotype for UNIX timestamp representation
|
||||
*/
|
||||
class TDate implements IDibiVariable
|
||||
{
|
||||
/**
|
||||
* Unix timestamp
|
||||
* @var int
|
||||
*/
|
||||
protected $time;
|
||||
|
||||
|
||||
|
||||
public function __construct($time = NULL)
|
||||
{
|
||||
if ($time === NULL)
|
||||
$this->time = time(); // current time
|
||||
|
||||
elseif (is_string($time))
|
||||
$this->time = strtotime($time); // try convert to timestamp
|
||||
|
||||
else
|
||||
$this->time = (int) $time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Format for SQL
|
||||
*
|
||||
* @param object destination DibiDriver
|
||||
* @param string optional modifier
|
||||
* @return string
|
||||
*/
|
||||
public function toSQL($driver, $modifier = NULL)
|
||||
{
|
||||
return date(
|
||||
$driver->formats['date'], // format according to driver's spec.
|
||||
$this->time
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getTimeStamp()
|
||||
{
|
||||
return $this->time;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pseudotype for datetime representation
|
||||
*/
|
||||
class TDateTime extends TDate
|
||||
{
|
||||
|
||||
public function toSQL($driver, $modifier = NULL)
|
||||
{
|
||||
return date(
|
||||
$driver->formats['datetime'], // format according to driver's spec.
|
||||
$this->time
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
164
dibi/libs/driver.php
Normal file
164
dibi/libs/driver.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi Common Driver
|
||||
*
|
||||
*/
|
||||
abstract class DibiDriver
|
||||
{
|
||||
/**
|
||||
* Current connection configuration
|
||||
* @var array
|
||||
*/
|
||||
protected
|
||||
$config;
|
||||
|
||||
/**
|
||||
* Describes how convert some datatypes to SQL command
|
||||
* @var array
|
||||
*/
|
||||
public $formats = array(
|
||||
'NULL' => "NULL", // NULL
|
||||
'TRUE' => "1", // boolean true
|
||||
'FALSE' => "0", // boolean false
|
||||
'date' => "'Y-m-d'", // format used by date()
|
||||
'datetime' => "'Y-m-d H:i:s'", // format used by date()
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* DibiDriver factory: creates object and connects to a database
|
||||
*
|
||||
* @param array connect configuration
|
||||
* @return bool|object DibiDriver object on success, FALSE or Exception on failure
|
||||
*/
|
||||
abstract static public function connect($config);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Driver initialization
|
||||
*
|
||||
* @param array connect configuration
|
||||
*/
|
||||
protected function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the configuration descriptor used by connect() to connect to database.
|
||||
* @see connect()
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query
|
||||
*
|
||||
* @param string SQL statement.
|
||||
* @return object|bool Result set object or TRUE on success, Exception on failure
|
||||
*/
|
||||
abstract public function query($sql);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query
|
||||
*
|
||||
* @return int number of rows or FALSE on error
|
||||
*/
|
||||
abstract public function affectedRows();
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query
|
||||
* @return int|bool int on success or FALSE on failure
|
||||
*/
|
||||
abstract public function insertId();
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
*/
|
||||
abstract public function begin();
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
*/
|
||||
abstract public function commit();
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
*/
|
||||
abstract public function rollback();
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Escapes the string
|
||||
* @param string unescaped string
|
||||
* @param bool quote string?
|
||||
* @return string escaped and optionally quoted string
|
||||
*/
|
||||
abstract public function escape($value, $appendQuotes = FALSE);
|
||||
|
||||
|
||||
/**
|
||||
* Quotes SQL identifier (table's or column's name, etc.)
|
||||
* @param string identifier
|
||||
* @return string quoted identifier
|
||||
*/
|
||||
abstract public function quoteName($value);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a information of the current database.
|
||||
*
|
||||
* @return DibiMetaData
|
||||
*/
|
||||
abstract public function getMetaData();
|
||||
|
||||
|
||||
|
||||
|
||||
} // class DibiDriver
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
67
dibi/libs/exception.php
Normal file
67
dibi/libs/exception.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi exception class
|
||||
*
|
||||
*/
|
||||
class DibiException extends Exception
|
||||
{
|
||||
private
|
||||
$info;
|
||||
|
||||
|
||||
public function __construct($message, $info=NULL) {
|
||||
|
||||
$this->info = $info;
|
||||
|
||||
if (isset($info['message']))
|
||||
$message = "$message: $info[message]";
|
||||
/*
|
||||
if (isset($info['sql']))
|
||||
$message .= "\n[SQL] $info[sql]";
|
||||
*/
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getSql()
|
||||
{
|
||||
return @$this->info['sql'];
|
||||
}
|
||||
|
||||
|
||||
} // class DibiException
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function is_error($var)
|
||||
{
|
||||
return ($var === FALSE) || ($var instanceof Exception);
|
||||
}
|
||||
|
||||
|
||||
?>
|
295
dibi/libs/parser.php
Normal file
295
dibi/libs/parser.php
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi parser
|
||||
*
|
||||
*/
|
||||
class DibiParser
|
||||
{
|
||||
private
|
||||
$modifier,
|
||||
$hasError,
|
||||
$driver;
|
||||
|
||||
|
||||
/**
|
||||
* Generates SQL
|
||||
*
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
public function parse($driver, $args)
|
||||
{
|
||||
$sql = '';
|
||||
$this->driver = $driver;
|
||||
$this->modifier = 0;
|
||||
$this->hasError = false;
|
||||
$command = null;
|
||||
$lastString = null;
|
||||
|
||||
foreach ($args as $index => $arg) {
|
||||
$sql .= ' '; // always add simple space
|
||||
|
||||
|
||||
// array processing (with or without modifier)
|
||||
if (is_array($arg)) {
|
||||
// determine type: set | values | list
|
||||
if ($this->modifier) {
|
||||
$type = $this->modifier;
|
||||
$this->modifier = false;
|
||||
} else {
|
||||
// autodetect
|
||||
if (is_int(key($arg)))
|
||||
$type = 'L'; // LIST
|
||||
else {
|
||||
if (!$command)
|
||||
$command = strtoupper(substr(ltrim($args[0]), 0, 6));
|
||||
|
||||
$type = $command == 'UPDATE' ? 'S' : 'V'; // SET | VALUES
|
||||
}
|
||||
}
|
||||
|
||||
// build array
|
||||
$vx = $kx = array();
|
||||
switch ($type) {
|
||||
case 'S': // SET
|
||||
foreach ($arg as $k => $v)
|
||||
$vx[] = $this->driver->quoteName($k) . '=' . $this->formatValue($v);
|
||||
|
||||
$sql .= implode(', ', $vx);
|
||||
break;
|
||||
|
||||
case 'V': // VALUES
|
||||
foreach ($arg as $k => $v) {
|
||||
$kx[] = $this->driver->quoteName($k);
|
||||
$vx[] = $this->formatValue($v);
|
||||
}
|
||||
|
||||
$sql .= '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
|
||||
break;
|
||||
|
||||
case 'L': // LIST
|
||||
foreach ($arg as $k => $v)
|
||||
$vx[] = $this->formatValue($v);
|
||||
|
||||
$sql .= implode(', ', $vx);
|
||||
break;
|
||||
|
||||
case 'N': // NAMES
|
||||
foreach ($arg as $v)
|
||||
$vx[] = $this->driver->quoteName($v);
|
||||
|
||||
$sql .= implode(', ', $vx);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->hasError = true;
|
||||
$sql .= "**Unknown modifier %$type**";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// after-modifier procession
|
||||
if ($this->modifier) {
|
||||
if ($arg instanceof IDibiVariable) {
|
||||
$sql .= $arg->toSql($this->driver, $this->modifier);
|
||||
$this->modifier = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_scalar($arg) && !is_null($arg)) { // array is already processed
|
||||
$this->hasError = true;
|
||||
$this->modifier = false;
|
||||
$sql .= '**Unexpected '.gettype($arg).'**';
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($this->modifier) {
|
||||
case "s": // string
|
||||
$sql .= $this->driver->escape($arg, TRUE);
|
||||
break;
|
||||
case 'T': // date
|
||||
$sql .= date($this->driver->formats['date'], is_string($arg) ? strtotime($arg) : $arg);
|
||||
break;
|
||||
case 't': // datetime
|
||||
$sql .= date($this->driver->formats['datetime'], is_string($arg) ? strtotime($arg) : $arg);
|
||||
break;
|
||||
case 'b': // boolean
|
||||
$sql .= $arg ? $this->driver->formats['TRUE'] : $this->driver->formats['FALSE'];
|
||||
break;
|
||||
case 'i':
|
||||
case 'u': // unsigned int
|
||||
case 'd': // signed int
|
||||
$sql .= (string) (int) $arg;
|
||||
break;
|
||||
case 'f': // float
|
||||
$sql .= (string) (float) $arg; // something like -9E-005 is accepted by SQL
|
||||
break;
|
||||
case 'n': // identifier name
|
||||
$sql .= $this->driver->quoteName($arg);
|
||||
break;
|
||||
default:
|
||||
$this->hasError = true;
|
||||
$sql .= "**Unknown modifier %$this->modifier**";
|
||||
}
|
||||
|
||||
$this->modifier = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// simple string means SQL
|
||||
if (is_string($arg)) {
|
||||
// double string warning
|
||||
// (problematic with dibi::queryStart & dibi::queryAdd
|
||||
// if ($lastString === $index-1)
|
||||
// trigger_error("Is seems there is error in SQL near '$arg'.", E_USER_WARNING);
|
||||
|
||||
$lastString = $index;
|
||||
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($arg, '`[\'"%');
|
||||
|
||||
if ($toSkip == strlen($arg)) {
|
||||
$sql .= $arg;
|
||||
} else {
|
||||
$sql .= substr($arg, 0, $toSkip)
|
||||
. preg_replace_callback('/
|
||||
(?=`|\[|\'|"|%) ## speed-up
|
||||
(?:
|
||||
`(.+?)`| ## 1) `identifier`
|
||||
\[(.+?)\]| ## 2) [identifier]
|
||||
(\')((?:\'\'|[^\'])*)\'| ## 3,4) string
|
||||
(")((?:""|[^"])*)"| ## 5,6) "string"
|
||||
%([a-zA-Z])$| ## 7) right modifier
|
||||
(\'|") ## 8) lone-quote
|
||||
)/xs',
|
||||
array($this, 'callback'),
|
||||
substr($arg, $toSkip)
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// default processing
|
||||
$sql .= $this->formatValue($arg);
|
||||
|
||||
} // for
|
||||
|
||||
|
||||
if ($this->hasError)
|
||||
return new DibiException('Errors during generating SQL', array('sql' => $sql));
|
||||
|
||||
return trim($sql);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private function formatValue($value)
|
||||
{
|
||||
if (is_string($value))
|
||||
return $this->driver->escape($value, TRUE);
|
||||
|
||||
if (is_int($value) || is_float($value))
|
||||
return (string) $value; // something like -9E-005 is accepted by SQL
|
||||
|
||||
if (is_bool($value))
|
||||
return $value ? $this->driver->formats['TRUE'] : $this->driver->formats['FALSE'];
|
||||
|
||||
if (is_null($value))
|
||||
return $this->driver->formats['NULL'];
|
||||
|
||||
if ($value instanceof IDibiVariable)
|
||||
return $value->toSql($this->driver);
|
||||
|
||||
$this->hasError = true;
|
||||
return '**Unsupported type '.gettype($value).'**';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* PREG callback for @see self::translate()
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
private function callback($matches)
|
||||
{
|
||||
// [1] => `ident`
|
||||
// [2] => [ident]
|
||||
// [3] => '
|
||||
// [4] => string
|
||||
// [5] => "
|
||||
// [6] => string
|
||||
// [7] => right modifier
|
||||
// [8] => lone-quote
|
||||
|
||||
if ($matches[1]) // SQL identifiers: `ident`
|
||||
return $this->driver->quoteName($matches[1]);
|
||||
|
||||
if ($matches[2]) // SQL identifiers: [ident]
|
||||
return $this->driver->quoteName($matches[2]);
|
||||
|
||||
if ($matches[3]) // SQL strings: '....'
|
||||
return $this->driver->escape( strtr($matches[4], array("''" => "'")), true);
|
||||
|
||||
if ($matches[5]) // SQL strings: "..."
|
||||
return $this->driver->escape( strtr($matches[6], array('""' => '"')), true);
|
||||
|
||||
if ($matches[7]) { // modifier
|
||||
$this->modifier = $matches[7];
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($matches[8]) { // string quote
|
||||
return '**Alone quote**';
|
||||
$this->hasError = true;
|
||||
}
|
||||
|
||||
die('this should be never executed');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // class DibiParser
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
396
dibi/libs/resultset.php
Normal file
396
dibi/libs/resultset.php
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - Database Abstraction Layer according to dgx
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* This source file is subject to the GNU GPL license.
|
||||
*
|
||||
* @author David Grudl aka -dgx- <dave@dgx.cz>
|
||||
* @link http://texy.info/dibi/
|
||||
* @copyright Copyright (c) 2005-2006 David Grudl
|
||||
* @license GNU GENERAL PUBLIC LICENSE
|
||||
* @package dibi
|
||||
* @category Database
|
||||
* @version 0.5alpha (2006-05-26) for PHP5
|
||||
*/
|
||||
|
||||
|
||||
// security - include dibi.php, not this file
|
||||
if (!defined('dibi')) die();
|
||||
|
||||
|
||||
|
||||
// PHP < 5.1 compatibility
|
||||
if (!interface_exists('Countable', false)) {
|
||||
interface Countable
|
||||
{
|
||||
function count();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi result-set abstract class
|
||||
*
|
||||
* <code>
|
||||
* $result = dibi::query('SELECT * FROM [table]');
|
||||
* $value = $result->fetchSingle();
|
||||
* $all = $result->fetchAll();
|
||||
* $assoc = $result->fetchAll('id');
|
||||
* $assoc = $result->fetchAll('active', 'id');
|
||||
* unset($result);
|
||||
* </code>
|
||||
*/
|
||||
abstract class DibiResult implements IteratorAggregate, Countable
|
||||
{
|
||||
/**
|
||||
* Column type in relation to PHP native type
|
||||
*/
|
||||
const
|
||||
FIELD_TEXT = 's', // as 'string'
|
||||
FIELD_BINARY = 'b',
|
||||
FIELD_BOOL = 'l', // as 'logical'
|
||||
FIELD_INTEGER = 'i',
|
||||
FIELD_FLOAT = 'f',
|
||||
FIELD_DATE = 'd',
|
||||
FIELD_DATETIME = 't',
|
||||
FIELD_UNKNOWN = '?',
|
||||
|
||||
// special
|
||||
FIELD_COUNTER = 'c'; // counter or autoincrement, is integer
|
||||
|
||||
|
||||
/**
|
||||
* Describes columns types
|
||||
* @var array
|
||||
*/
|
||||
protected $convert;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
abstract public function seek($row);
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set
|
||||
* @return int
|
||||
*/
|
||||
abstract public function rowCount();
|
||||
|
||||
/**
|
||||
* Gets an array of field names
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getFields();
|
||||
|
||||
/**
|
||||
* Gets an array of meta informations about column
|
||||
* @param string column name
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getMetaData($field);
|
||||
|
||||
/**
|
||||
* Acquires ....
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function detectTypes();
|
||||
|
||||
/**
|
||||
* Frees the resources allocated for this result set
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function free();
|
||||
|
||||
/**
|
||||
* Fetches the row at current position and moves the internal cursor to the next position
|
||||
* internal usage only
|
||||
* @return array|FALSE array() on success, FALSE if no next record
|
||||
*/
|
||||
abstract protected function doFetch();
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the row at current position, process optional type conversion
|
||||
* and moves the internal cursor to the next position
|
||||
* @return array|FALSE array() on success, FALSE if no next record
|
||||
*/
|
||||
final public function fetch()
|
||||
{
|
||||
$rec = $this->doFetch();
|
||||
if (!is_array($rec))
|
||||
return FALSE;
|
||||
|
||||
// types-converting?
|
||||
if ($t = $this->convert) { // little speed-up
|
||||
foreach ($rec as $key => $value) {
|
||||
if (isset($t[$key]))
|
||||
$rec[$key] = $this->convert($value, $t[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $rec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Like fetch(), but returns only first field
|
||||
* @return mixed value on success, FALSE if no next record
|
||||
*/
|
||||
final function fetchSingle()
|
||||
{
|
||||
$rec = $this->doFetch();
|
||||
if (!is_array($rec))
|
||||
return FALSE;
|
||||
|
||||
// types-converting?
|
||||
if ($t = $this->convert) { // little speed-up
|
||||
$value = reset($rec);
|
||||
$key = key($rec);
|
||||
return isset($t[$key])
|
||||
? $this->convert($value, $t[$key])
|
||||
: $value;
|
||||
}
|
||||
|
||||
return reset($rec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all records from table. Records , but returns only first field
|
||||
* @param string associative colum [, param, ... ]
|
||||
* @return array
|
||||
*/
|
||||
final function fetchAll()
|
||||
{
|
||||
@$this->seek(0);
|
||||
$rec = $this->fetch();
|
||||
if (!$rec)
|
||||
return array(); // empty resultset
|
||||
|
||||
$assocBy = func_get_args();
|
||||
$arr = array();
|
||||
|
||||
if (!$assocBy) { // no associative array
|
||||
$value = count($rec) == 1 ? key($rec) : NULL;
|
||||
do {
|
||||
$arr[] = $value === NULL ? $rec : $rec[$value];
|
||||
} while ($rec = $this->fetch());
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
do { // make associative arrays
|
||||
foreach ($assocBy as $n => $assoc) {
|
||||
$val[$n] = $rec[$assoc];
|
||||
unset($rec[$assoc]);
|
||||
}
|
||||
|
||||
foreach ($assocBy as $n => $assoc) {
|
||||
if ($n == 0)
|
||||
$tmp = &$arr[ $val[$n] ];
|
||||
else
|
||||
$tmp = &$tmp[$assoc][ $val[$n] ];
|
||||
|
||||
if ($tmp === NULL)
|
||||
$tmp = $rec;
|
||||
}
|
||||
} while ($rec = $this->fetch());
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all records from table like $key => $value pairs
|
||||
* @return array
|
||||
*/
|
||||
final function fetchPairs($key, $value)
|
||||
{
|
||||
@$this->seek(0);
|
||||
$rec = $this->fetch();
|
||||
if (!$rec)
|
||||
return array(); // empty resultset
|
||||
|
||||
$arr = array();
|
||||
do {
|
||||
$arr[ $rec[$key] ] = $rec[$value];
|
||||
} while ($rec = $this->fetch());
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Automatically frees the resources allocated for this result set
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
@$this->free();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function setType($field, $type = NULL)
|
||||
{
|
||||
if ($field === TRUE)
|
||||
$this->detectTypes();
|
||||
|
||||
elseif (is_array($field))
|
||||
$this->convert = $field;
|
||||
|
||||
else
|
||||
$this->convert[$field] = $type;
|
||||
}
|
||||
|
||||
|
||||
/** is this needed? */
|
||||
public function getType($field)
|
||||
{
|
||||
return isset($this->convert[$field]) ? $this->convert[$field] : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function convert($value, $type)
|
||||
{
|
||||
if ($value === NULL || $value === FALSE)
|
||||
return $value;
|
||||
|
||||
static $conv = array(
|
||||
self::FIELD_TEXT => 'string',
|
||||
self::FIELD_BINARY => 'string',
|
||||
self::FIELD_BOOL => 'bool',
|
||||
self::FIELD_INTEGER => 'int',
|
||||
self::FIELD_FLOAT => 'float',
|
||||
self::FIELD_COUNTER => 'int',
|
||||
);
|
||||
|
||||
if (isset($conv[$type])) {
|
||||
settype($value, $conv[$type]);
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($type == self::FIELD_DATE)
|
||||
return new TDate($value); // !!! experimental
|
||||
|
||||
if ($type == self::FIELD_DATETIME)
|
||||
return new TDateTime($value); // !!! experimental
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/** these are the required IteratorAggregate functions */
|
||||
public function getIterator($offset = NULL, $count = NULL)
|
||||
{
|
||||
return new DibiResultIterator($this, $offset, $count);
|
||||
}
|
||||
/** end required IteratorAggregate functions */
|
||||
|
||||
|
||||
/** these are the required Countable functions */
|
||||
public function count()
|
||||
{
|
||||
return $this->rowCount();
|
||||
}
|
||||
/** end required Countable functions */
|
||||
|
||||
} // class DibiResult
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Basic Result set iterator.
|
||||
*
|
||||
* This can be returned by DibiResult::getIterator() method or directly using foreach:
|
||||
* <code>
|
||||
* $result = dibi::query('SELECT * FROM table');
|
||||
* foreach ($result as $fields) {
|
||||
* print_r($fields);
|
||||
* }
|
||||
* unset($result);
|
||||
* </code>
|
||||
*
|
||||
* Optionally you can specify offset and limit:
|
||||
* <code>
|
||||
* foreach ($result->getIterator(2, 3) as $fields) {
|
||||
* print_r($fields);
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
class DibiResultIterator implements Iterator
|
||||
{
|
||||
private
|
||||
$result,
|
||||
$offset,
|
||||
$count,
|
||||
$record,
|
||||
$row;
|
||||
|
||||
|
||||
public function __construct(DibiResult $result, $offset = NULL, $count = NULL)
|
||||
{
|
||||
$this->result = $result;
|
||||
$this->offset = (int) $offset;
|
||||
$this->count = $count === NULL ? PHP_INT_MAX : (int) $count;
|
||||
}
|
||||
|
||||
|
||||
/** these are the required Iterator functions */
|
||||
public function rewind()
|
||||
{
|
||||
$this->row = 0;
|
||||
@$this->result->seek($this->offset);
|
||||
$this->record = $this->result->fetch();
|
||||
}
|
||||
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->row;
|
||||
}
|
||||
|
||||
|
||||
public function current()
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
|
||||
public function next()
|
||||
{
|
||||
$this->record = $this->result->fetch();
|
||||
$this->row++;
|
||||
}
|
||||
|
||||
|
||||
public function valid()
|
||||
{
|
||||
return is_array($this->record) && ($this->row < $this->count);
|
||||
}
|
||||
/** end required Iterator functions */
|
||||
|
||||
|
||||
} // class DibiResultIterator
|
||||
|
||||
|
||||
|
||||
?>
|
Reference in New Issue
Block a user