1
0
mirror of https://github.com/dg/dibi.git synced 2025-08-30 09:19:48 +02:00

Compare commits

..

1 Commits
v2.2.4 ... v0.5

Author SHA1 Message Date
David Grudl
3383676830 Release 0.5b 2006-06-04 23:10:34 +00:00
94 changed files with 3411 additions and 13277 deletions

2
.gitattributes vendored
View File

@@ -1,2 +0,0 @@
.gitattributes export-ignore
.gitignore export-ignore

2
.gitignore vendored
View File

@@ -1,2 +0,0 @@
/vendor
/composer.lock

View File

@@ -1,25 +0,0 @@
{
"name": "dibi/dibi",
"description": "Dibi is Database Abstraction Library for PHP",
"keywords": ["database", "dbal", "mysql", "postgresql", "sqlite", "mssql", "oracle", "access", "pdo", "odbc"],
"homepage": "http://dibiphp.com",
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
}
],
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"tracy/tracy": "~2.2"
},
"replace": {
"dg/dibi": "self.version"
},
"autoload": {
"classmap": ["dibi/"]
}
}

21
copyright.txt Normal file
View File

@@ -0,0 +1,21 @@
Copyright notice
----------------
dibi (C) David Grudl, 2005-2006 <dave@dgx.cz>
For more information, visit the homepage http://texy.info/dibi
or author's weblog: http://www.dgx.cz/trine/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

View File

@@ -0,0 +1,33 @@
<?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.5b (2006-05-31) 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');
abstract class DibiDriver{protected$config;public$formats=array('NULL'=>"NULL",'TRUE'=>"1",'FALSE'=>"0",'date'=>"'Y-m-d'",'datetime'=>"'Y-m-d H:i:s'",);abstract static public function connect($config);protected function __construct($config){$this->config=$config;}public function getConfig(){return$this->config;}abstract public function query($sql);abstract public function affectedRows();abstract public function insertId();abstract public function begin();abstract public function commit();abstract public function rollback();abstract public function escape($value,$appendQuotes=FALSE);abstract public function quoteName($value);abstract public function getMetaData();}
if(!interface_exists('Countable',false)){interface Countable{function count();}}abstract class DibiResult implements IteratorAggregate,Countable{const FIELD_TEXT='s',FIELD_BINARY='b',FIELD_BOOL='l',FIELD_INTEGER='i',FIELD_FLOAT='f',FIELD_DATE='d',FIELD_DATETIME='t',FIELD_UNKNOWN='?',FIELD_COUNTER='c';protected$convert;abstract public function seek($row);abstract public function rowCount();abstract public function getFields();abstract public function getMetaData($field);abstract protected function detectTypes();abstract protected function free();abstract protected function doFetch();final public function fetch(){$rec=$this->doFetch();if(!is_array($rec))return FALSE;if($t=$this->convert){foreach($rec as$key=>$value){if(isset($t[$key]))$rec[$key]=$this->convert($value,$t[$key]);}}return$rec;}final function fetchSingle(){$rec=$this->doFetch();if(!is_array($rec))return FALSE;if($t=$this->convert){$value=reset($rec);$key=key($rec);return isset($t[$key])?$this->convert($value,$t[$key]):$value;}return reset($rec);}final function fetchAll(){@$this->seek(0);$rec=$this->fetch();if(!$rec)return array();$assocBy=func_get_args();$arr=array();if(!$assocBy){$value=count($rec)==1?key($rec):NULL;do{$arr[]=$value===NULL?$rec:$rec[$value];}while($rec=$this->fetch());return$arr;}do{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;}final function fetchPairs($key,$value){@$this->seek(0);$rec=$this->fetch();if(!$rec)return array();$arr=array();do{$arr[$rec[$key]]=$rec[$value];}while($rec=$this->fetch());return$arr;}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;}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);if($type==self::FIELD_DATETIME)return new TDateTime($value);return$value;}public function getIterator($offset=NULL,$count=NULL){return new DibiResultIterator($this,$offset,$count);}public function count(){return$this->rowCount();}}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?2147483647:(int)$count;}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);}}
class DibiParser{private$modifier,$hasError,$driver;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.=' ';if(is_array($arg)){if($this->modifier){$type=$this->modifier;$this->modifier=false;}else{if(is_int(key($arg)))$type='L';else{if(!$command)$command=strtoupper(substr(ltrim($args[0]),0,6));$type=$command=='UPDATE'?'S':'V';}}$vx=$kx=array();switch($type){case'S':foreach($arg as$k=>$v)$vx[]=$this->driver->quoteName($k).'='.$this->formatValue($v);$sql.=implode(', ',$vx);break;case'V':foreach($arg as$k=>$v){$kx[]=$this->driver->quoteName($k);$vx[]=$this->formatValue($v);}$sql.='('.implode(', ',$kx).') VALUES ('.implode(', ',$vx).')';break;case'L':foreach($arg as$k=>$v)$vx[]=$this->formatValue($v);$sql.=implode(', ',$vx);break;case'N':foreach($arg as$v)$vx[]=$this->driver->quoteName($v);$sql.=implode(', ',$vx);break;default:$this->hasError=true;$sql.="**Unknown modifier %$type**";}continue;}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)){$this->hasError=true;$this->modifier=false;$sql.='**Unexpected '.gettype($arg).'**';continue;}switch($this->modifier){case"s":$sql.=$this->driver->escape($arg,TRUE);break;case'T':$sql.=date($this->driver->formats['date'],is_string($arg)?strtotime($arg):$arg);break;case't':$sql.=date($this->driver->formats['datetime'],is_string($arg)?strtotime($arg):$arg);break;case'b':$sql.=$arg?$this->driver->formats['TRUE']:$this->driver->formats['FALSE'];break;case'i':case'u':case'd':$sql.=(string)(int)$arg;break;case'f':$sql.=(string)(float)$arg;break;case'n':$sql.=$this->driver->quoteName($arg);break;default:$this->hasError=true;$sql.="**Unknown modifier %$this->modifier**";}$this->modifier=false;continue;}if(is_string($arg)){$lastString=$index;$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;}$sql.=$this->formatValue($arg);}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;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).'**';}private function callback($matches){if($matches[1])return$this->driver->quoteName($matches[1]);if($matches[2])return$this->driver->quoteName($matches[2]);if($matches[3])return$this->driver->escape(strtr($matches[4],array("''"=>"'")),true);if($matches[5])return$this->driver->escape(strtr($matches[6],array('""'=>'"')),true);if($matches[7]){$this->modifier=$matches[7];return'';}if($matches[8]){return'**Alone quote**';$this->hasError=true;}die('this should be never executed');}}
class DibiException extends Exception{private$info;public function __construct($message,$info=NULL){$this->info=$info;if(isset($info['message']))$message="$message: $info[message]";parent::__construct($message);}public function getSql(){return@$this->info['sql'];}}function is_error($var){return($var===FALSE)||($var instanceof Exception);}
if(function_exists('date_default_timezone_set'))date_default_timezone_set('Europe/Prague');class TDate implements IDibiVariable{protected$time;public function __construct($time=NULL){if($time===NULL)$this->time=time();elseif(is_string($time))$this->time=strtotime($time);else$this->time=(int)$time;}public function toSQL($driver,$modifier=NULL){return date($driver->formats['date'],$this->time);}public function getTimeStamp(){return$this->time;}}class TDateTime extends TDate{public function toSQL($driver,$modifier=NULL){return date($driver->formats['datetime'],$this->time);}} interface IDibiVariable{public function toSQL($driver,$modifier=NULL);}class dibi{static private$registry=array();static private$conn;static private$parser;static public$sql;static public$error;static public$logfile;static public$debug=false;static private$query=array();static public function connect($config,$name='def'){if(!self::$parser)self::$parser=new DibiParser();if(isset(self::$registry[$name]))return new DibiException("Connection named '$name' already exists.");if(empty($config['driver']))return new DibiException('Driver is not specified.');$className="Dibi$config[driver]Driver"; if(!class_exists($className))return new DibiException("Unable to create instance of dibi driver class '$className'.");$conn=call_user_func(array($className,'connect'),$config);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)){if(self::$debug)echo'[dibi error] '.$conn->getMessage();return$conn;}self::$conn=self::$registry[$name]=$conn;return TRUE;}static public function isConnected(){return(bool)self::$conn;}static public function getConnection($name=NULL){return$name===NULL?self::$conn:@self::$registry[$name];}static public function activate($name){if(!isset(self::$registry[$name]))return FALSE;self::$conn=self::$registry[$name];return TRUE;}static public function query(){if(!self::$conn)return new DibiException('Dibi is not connected to DB');$args=func_num_args()?func_get_args():self::$query;self::$query=array();self::$sql=self::$parser->parse(self::$conn,$args);if(is_error(self::$sql))return self::$sql;$timer=-microtime(true);$res=self::$conn->query(self::$sql);$timer+=microtime(true);if(is_error($res)){if(self::$debug){echo'[dibi error] '.$res->getMessage();self::dump(self::$sql);}self::$error=$res;}else{self::$error=FALSE;}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);}static public function test(){if(!self::$conn)return FALSE;$args=func_num_args()?func_get_args():self::$query;self::$query=array();$sql=self::$parser->parse(self::$conn,$args);if(is_error($sql)){self::dump($sql->getSql());return$sql->getSql();}else{self::dump($sql);return$sql;}}static public function insertId(){if(!self::$conn)return FALSE;return self::$conn->insertId();}static public function affectedRows(){if(!self::$conn)return FALSE;return self::$conn->affectedRows();}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',);foreach($newline as$word)$sql=preg_replace('#\b'.$word.'\b#',"\n\$0",$sql);$sql=trim($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>';}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 DibiMySqlDriver extends DibiDriver{private$conn,$insertId=FALSE,$affectedRows=FALSE;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('mysql'))return new DibiException("PHP extension 'mysql' is not loaded");if(empty($config['host']))$config['host']='localhost';if(@$config['protocol']==='unix')$host=':'.$config['host'];else$host=$config['host'].(empty($config['port'])?'':$config['port']);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);}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){$this->insertId=$this->affectedRows=FALSE;$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,));$this->affectedRows=mysql_affected_rows($this->conn);if($this->affectedRows<0)$this->affectedRows=FALSE;$this->insertId=mysql_insert_id($this->conn);if($this->insertId<1)$this->insertId=FALSE;return TRUE;}public function affectedRows(){return$this->affectedRows;}public function insertId(){return$this->insertId;}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);}}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(){if($this->meta===NULL)$this->createMeta();return array_keys($this->meta);}protected function detectTypes(){if($this->meta===NULL)$this->createMeta();}public function getMetaData($field){if($this->meta===NULL)$this->createMeta();return isset($this->meta[$field])?$this->meta[$field]:FALSE;}private function createMeta(){static$types=array('ENUM'=>self::FIELD_TEXT,'SET'=>self::FIELD_TEXT,'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']))$info['type']=self::FIELD_COUNTER;else{$info['type']=isset($types[$native])?$types[$native]:self::FIELD_UNKNOWN;}$name=mysql_field_name($this->resource,$index);$this->meta[$name]=$info;$this->convert[$name]=$info['type'];}}}
class DibiMySqliDriver extends DibiDriver{private$conn,$insertId=FALSE,$affectedRows=FALSE;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){$this->insertId=$this->affectedRows=FALSE;$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));$this->affectedRows=mysqli_affected_rows($this->conn);if($this->affectedRows<0)$this->affectedRows=FALSE;$this->insertId=mysqli_insert_id($this->conn);if($this->insertId<1)$this->insertId=FALSE;return TRUE;}public function affectedRows(){return$this->affectedRows;}public function insertId(){return$this->insertId;}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 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(){if($this->meta===NULL)$this->createMeta();return array_keys($this->meta);}protected function detectTypes(){if($this->meta===NULL)$this->createMeta();}public function getMetaData($field){if($this->meta===NULL)$this->createMeta();return isset($this->meta[$field])?$this->meta[$field]:FALSE;}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_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,MYSQLI_TYPE_SET=>self::FIELD_TEXT,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)$info['type']=self::FIELD_COUNTER;else{$info['type']=isset($types[$native])?$types[$native]:self::FIELD_UNKNOWN;}$this->meta[$info['name']]=$info;$this->convert[$info['name']]=$info['type'];}}}
class DibiOdbcDriver extends DibiDriver{private$conn,$affectedRows=FALSE;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){$this->affectedRows=FALSE;$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));$this->affectedRows=odbc_num_rows($this->conn);if($this->affectedRows<0)$this->affectedRows=FALSE;return TRUE;}public function affectedRows(){return$this->affectedRows;}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 DibiOdbcResult extends DibiResult{private$resource,$meta,$row=0;public function __construct($resource){$this->resource=$resource;}public function rowCount(){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(){if($this->meta===NULL)$this->createMeta();return array_keys($this->meta);}protected function detectTypes(){if($this->meta===NULL)$this->createMeta();}public function getMetaData($field){if($this->meta===NULL)$this->createMeta();return isset($this->meta[$field])?$this->meta[$field]:FALSE;}private function createMeta(){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,);$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 DibiSqliteDriver extends DibiDriver{private$conn,$insertId=FALSE,$affectedRows=FALSE;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){$this->insertId=$this->affectedRows=FALSE;$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);$this->affectedRows=sqlite_changes($this->conn);if($this->affectedRows<0)$this->affectedRows=FALSE;$this->insertId=sqlite_last_insert_rowid($this->conn);if($this->insertId<1)$this->insertId=FALSE;return TRUE;}public function affectedRows(){return$this->affectedRows;}public function insertId(){return$this->insertId;}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 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(){if($this->meta===NULL)$this->createMeta();return array_keys($this->meta);}protected function detectTypes(){if($this->meta===NULL)$this->createMeta();}public function getMetaData($field){if($this->meta===NULL)$this->createMeta();return isset($this->meta[$field])?$this->meta[$field]:FALSE;}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;}}}?>

View File

@@ -1,55 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
/**
* Dibi extension for Nette Framework 2.0. Creates 'connection' service.
*
* @author David Grudl
* @package dibi\nette
* @phpversion 5.3
*/
class DibiNette20Extension extends Nette\Config\CompilerExtension
{
public function loadConfiguration()
{
$container = $this->getContainerBuilder();
$config = $this->getConfig();
$useProfiler = isset($config['profiler'])
? $config['profiler']
: !$container->parameters['productionMode'];
unset($config['profiler']);
if (isset($config['flags'])) {
$flags = 0;
foreach ((array) $config['flags'] as $flag) {
$flags |= constant($flag);
}
$config['flags'] = $flags;
}
$connection = $container->addDefinition($this->prefix('connection'))
->setClass('DibiConnection', array($config));
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setClass('DibiNettePanel')
->addSetup('Nette\Diagnostics\Debugger::$bar->addPanel(?)', array('@self'))
->addSetup('Nette\Diagnostics\Debugger::$blueScreen->addPanel(?)', array('DibiNettePanel::renderException'));
$connection->addSetup('$service->onEvent[] = ?', array(array($panel, 'logEvent')));
}
}
}

View File

@@ -1,17 +0,0 @@
# Requires Nette Framework 2.0 for PHP 5.3
#
# In bootstrap.php append these lines after line $configurator = new Nette\Config\Configurator;
#
# $configurator->onCompile[] = function($configurator, $compiler) {
# $compiler->addExtension('dibi', new DibiNette20Extension);
# };
#
# This will create service named 'dibi.connection'.
common:
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: TRUE

View File

@@ -1,51 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* Dibi extension for Nette Framework 2.1. Creates 'connection' service.
*
* @author David Grudl
* @package dibi\nette
* @phpversion 5.3
*/
class DibiNette21Extension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$container = $this->getContainerBuilder();
$config = $this->getConfig();
$useProfiler = isset($config['profiler'])
? $config['profiler']
: $container->parameters['debugMode'];
unset($config['profiler']);
if (isset($config['flags'])) {
$flags = 0;
foreach ((array) $config['flags'] as $flag) {
$flags |= constant($flag);
}
$config['flags'] = $flags;
}
$connection = $container->addDefinition($this->prefix('connection'))
->setClass('DibiConnection', array($config));
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setClass('DibiNettePanel')
->addSetup('Nette\Diagnostics\Debugger::getBar()->addPanel(?)', array('@self'))
->addSetup('Nette\Diagnostics\Debugger::getBlueScreen()->addPanel(?)', array('DibiNettePanel::renderException'));
$connection->addSetup('$service->onEvent[] = ?', array(array($panel, 'logEvent')));
}
}
}

View File

@@ -1,166 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
if (interface_exists('Nette\Diagnostics\IBarPanel')) {
class_alias('Nette\Diagnostics\IBarPanel', 'IBarPanel');
}
/**
* Dibi panel for Nette\Diagnostics.
*
* @author David Grudl
* @package dibi\nette
*/
class DibiNettePanel extends DibiObject implements IBarPanel
{
/** @var int maximum SQL length */
static public $maxLength = 1000;
/** @var bool explain queries? */
public $explain;
/** @var int */
public $filter;
/** @var array */
private $events = array();
public function __construct($explain = TRUE, $filter = NULL)
{
$this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
$this->explain = $explain;
}
public function register(DibiConnection $connection)
{
if (is_callable('Nette\Diagnostics\Debugger::enable') && !class_exists('NDebugger')) {
class_alias('Nette\Diagnostics\Debugger', 'NDebugger'); // PHP 5.2 code compatibility
}
if (is_callable('NDebugger::enable') && is_callable('NDebugger::getBlueScreen')) { // Nette Framework 2.1
NDebugger::getBar()->addPanel($this);
NDebugger::getBlueScreen()->addPanel(array(__CLASS__, 'renderException'));
$connection->onEvent[] = array($this, 'logEvent');
} elseif (is_callable('NDebugger::enable')) { // Nette Framework 2.0 (for PHP 5.3 or PHP 5.2 prefixed)
NDebugger::$bar && NDebugger::$bar->addPanel($this);
NDebugger::$blueScreen && NDebugger::$blueScreen->addPanel(array(__CLASS__, 'renderException'), __CLASS__);
$connection->onEvent[] = array($this, 'logEvent');
} elseif (is_callable('Debugger::enable') && !is_callable('Debugger::getBlueScreen')) { // Nette Framework 2.0 for PHP 5.2 non-prefixed
Debugger::$bar && Debugger::$bar->addPanel($this);
Debugger::$blueScreen && Debugger::$blueScreen->addPanel(array(__CLASS__, 'renderException'), __CLASS__);
$connection->onEvent[] = array($this, 'logEvent');
}
}
/**
* After event notification.
* @return void
*/
public function logEvent(DibiEvent $event)
{
if (($event->type & $this->filter) === 0) {
return;
}
$this->events[] = $event;
}
/**
* Returns blue-screen custom tab.
* @return mixed
*/
public static function renderException($e)
{
if ($e instanceof DibiException && $e->getSql()) {
return array(
'tab' => 'SQL',
'panel' => dibi::dump($e->getSql(), TRUE),
);
}
}
/**
* Returns HTML code for custom tab. (Nette\Diagnostics\IBarPanel)
* @return mixed
*/
public function getTab()
{
$totalTime = 0;
foreach ($this->events as $event) {
$totalTime += $event->time;
}
return '<span title="dibi"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEYSURBVBgZBcHPio5hGAfg6/2+R980k6wmJgsJ5U/ZOAqbSc2GnXOwUg7BESgLUeIQ1GSjLFnMwsKGGg1qxJRmPM97/1zXFAAAAEADdlfZzr26miup2svnelq7d2aYgt3rebl585wN6+K3I1/9fJe7O/uIePP2SypJkiRJ0vMhr55FLCA3zgIAOK9uQ4MS361ZOSX+OrTvkgINSjS/HIvhjxNNFGgQsbSmabohKDNoUGLohsls6BaiQIMSs2FYmnXdUsygQYmumy3Nhi6igwalDEOJEjPKP7CA2aFNK8Bkyy3fdNCg7r9/fW3jgpVJbDmy5+PB2IYp4MXFelQ7izPrhkPHB+P5/PjhD5gCgCenx+VR/dODEwD+A3T7nqbxwf1HAAAAAElFTkSuQmCC" />'
. count($this->events) . ' queries'
. ($totalTime ? sprintf(' / %0.1f ms', $totalTime * 1000) : '')
. '</span>';
}
/**
* Returns HTML code for custom panel. (Nette\Diagnostics\IBarPanel)
* @return mixed
*/
public function getPanel()
{
$totalTime = $s = NULL;
$h = 'htmlSpecialChars';
foreach ($this->events as $event) {
$totalTime += $event->time;
$explain = NULL; // EXPLAIN is called here to work SELECT FOUND_ROWS()
if ($this->explain && $event->type === DibiEvent::SELECT) {
try {
$backup = array($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime);
$event->connection->onEvent = NULL;
$cmd = is_string($this->explain) ? $this->explain : ($event->connection->getConfig('driver') === 'oracle' ? 'EXPLAIN PLAN' : 'EXPLAIN');
$explain = dibi::dump($event->connection->nativeQuery("$cmd $event->sql"), TRUE);
} catch (DibiException $e) {
}
list($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime) = $backup;
}
$s .= '<tr><td>' . sprintf('%0.3f', $event->time * 1000);
if ($explain) {
static $counter;
$counter++;
$s .= "<br /><a href='#nette-debug-DibiProfiler-row-$counter' class='nette-toggler nette-toggle-collapsed' rel='#nette-debug-DibiProfiler-row-$counter'>explain</a>";
}
$s .= '</td><td class="nette-DibiProfiler-sql">' . dibi::dump(strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql, TRUE);
if ($explain) {
$s .= "<div id='nette-debug-DibiProfiler-row-$counter' class='nette-collapsed'>{$explain}</div>";
}
if ($event->source) {
$helpers = 'Nette\Diagnostics\Helpers';
if (!class_exists($helpers)) {
$helpers = class_exists('NDebugHelpers') ? 'NDebugHelpers' : 'DebugHelpers';
}
$s .= call_user_func(array($helpers, 'editorLink'), $event->source[0], $event->source[1])->class('nette-DibiProfiler-source');
}
$s .= "</td><td>{$event->count}</td><td>{$h($event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name'))}</td></tr>";
}
return empty($this->events) ? '' :
'<style> #nette-debug td.nette-DibiProfiler-sql { background: white !important }
#nette-debug .nette-DibiProfiler-source { color: #999 !important }
#nette-debug nette-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
<h1>Queries: ' . count($this->events) . ($totalTime === NULL ? '' : sprintf(', time: %0.3f ms', $totalTime * 1000)) . '</h1>
<div class="nette-inner nette-DibiProfiler">
<table>
<tr><th>Time&nbsp;ms</th><th>SQL Statement</th><th>Rows</th><th>Connection</th></tr>' . $s . '
</table>
</div>';
}
}

View File

@@ -1,12 +0,0 @@
# This will create service named 'dibi.connection'.
# Requires Nette Framework 2.1
extensions:
dibi: DibiNette21Extension
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: TRUE

View File

@@ -1,52 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
namespace Dibi\Bridges\Nette;
use dibi;
use Nette;
/**
* Dibi extension for Nette Framework 2.2. Creates 'connection' & 'panel' services.
*
* @author David Grudl
* @package dibi\nette
*/
class DibiExtension22 extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$container = $this->getContainerBuilder();
$config = $this->getConfig();
$useProfiler = isset($config['profiler'])
? $config['profiler']
: class_exists('Tracy\Debugger') && $container->parameters['debugMode'];
unset($config['profiler']);
if (isset($config['flags'])) {
$flags = 0;
foreach ((array) $config['flags'] as $flag) {
$flags |= constant($flag);
}
$config['flags'] = $flags;
}
$connection = $container->addDefinition($this->prefix('connection'))
->setClass('DibiConnection', array($config));
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setClass('Dibi\Bridges\Tracy\Panel');
$connection->addSetup(array($panel, 'register'), array($connection));
}
}
}

View File

@@ -1,12 +0,0 @@
# This will create service named 'dibi.connection'.
# Requires Nette Framework 2.2
extensions:
dibi: Dibi\Bridges\Nette\DibiExtension22
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: TRUE

View File

@@ -1,146 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
namespace Dibi\Bridges\Tracy;
use dibi;
use Tracy;
/**
* Dibi panel for Tracy.
* @package dibi\nette
* @author David Grudl
*/
class Panel extends \DibiObject implements Tracy\IBarPanel
{
/** @var int maximum SQL length */
static public $maxLength = 1000;
/** @var bool explain queries? */
public $explain;
/** @var int */
public $filter;
/** @var array */
private $events = array();
public function __construct($explain = TRUE, $filter = NULL)
{
$this->filter = $filter ? (int) $filter : \DibiEvent::QUERY;
$this->explain = $explain;
}
public function register(\DibiConnection $connection)
{
Tracy\Debugger::getBar()->addPanel($this);
Tracy\Debugger::getBlueScreen()->addPanel(array(__CLASS__, 'renderException'));
$connection->onEvent[] = array($this, 'logEvent');
}
/**
* After event notification.
* @return void
*/
public function logEvent(\DibiEvent $event)
{
if (($event->type & $this->filter) === 0) {
return;
}
$this->events[] = $event;
}
/**
* Returns blue-screen custom tab.
* @return mixed
*/
public static function renderException($e)
{
if ($e instanceof \DibiException && $e->getSql()) {
return array(
'tab' => 'SQL',
'panel' => dibi::dump($e->getSql(), TRUE),
);
}
}
/**
* Returns HTML code for custom tab. (Tracy\IBarPanel)
* @return mixed
*/
public function getTab()
{
$totalTime = 0;
foreach ($this->events as $event) {
$totalTime += $event->time;
}
return '<span title="dibi"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEYSURBVBgZBcHPio5hGAfg6/2+R980k6wmJgsJ5U/ZOAqbSc2GnXOwUg7BESgLUeIQ1GSjLFnMwsKGGg1qxJRmPM97/1zXFAAAAEADdlfZzr26miup2svnelq7d2aYgt3rebl585wN6+K3I1/9fJe7O/uIePP2SypJkiRJ0vMhr55FLCA3zgIAOK9uQ4MS361ZOSX+OrTvkgINSjS/HIvhjxNNFGgQsbSmabohKDNoUGLohsls6BaiQIMSs2FYmnXdUsygQYmumy3Nhi6igwalDEOJEjPKP7CA2aFNK8Bkyy3fdNCg7r9/fW3jgpVJbDmy5+PB2IYp4MXFelQ7izPrhkPHB+P5/PjhD5gCgCenx+VR/dODEwD+A3T7nqbxwf1HAAAAAElFTkSuQmCC" />'
. count($this->events) . ' queries'
. ($totalTime ? sprintf(' / %0.1f ms', $totalTime * 1000) : '')
. '</span>';
}
/**
* Returns HTML code for custom panel. (Tracy\IBarPanel)
* @return mixed
*/
public function getPanel()
{
$totalTime = $s = NULL;
$h = 'htmlSpecialChars';
foreach ($this->events as $event) {
$totalTime += $event->time;
$explain = NULL; // EXPLAIN is called here to work SELECT FOUND_ROWS()
if ($this->explain && $event->type === \DibiEvent::SELECT) {
try {
$backup = array($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime);
$event->connection->onEvent = NULL;
$cmd = is_string($this->explain) ? $this->explain : ($event->connection->getConfig('driver') === 'oracle' ? 'EXPLAIN PLAN' : 'EXPLAIN');
$explain = dibi::dump($event->connection->nativeQuery("$cmd $event->sql"), TRUE);
} catch (\DibiException $e) {
}
list($event->connection->onEvent, dibi::$numOfQueries, dibi::$totalTime) = $backup;
}
$s .= '<tr><td>' . sprintf('%0.3f', $event->time * 1000);
if ($explain) {
static $counter;
$counter++;
$s .= "<br /><a href='#tracy-debug-DibiProfiler-row-$counter' class='tracy-toggle tracy-collapsed' rel='#tracy-debug-DibiProfiler-row-$counter'>explain</a>";
}
$s .= '</td><td class="tracy-DibiProfiler-sql">' . dibi::dump(strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql, TRUE);
if ($explain) {
$s .= "<div id='tracy-debug-DibiProfiler-row-$counter' class='tracy-collapsed'>{$explain}</div>";
}
if ($event->source) {
$s .= Tracy\Helpers::editorLink($event->source[0], $event->source[1]);//->class('tracy-DibiProfiler-source');
}
$s .= "</td><td>{$event->count}</td><td>{$h($event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name'))}</td></tr>";
}
return empty($this->events) ? '' :
'<style> #tracy-debug td.tracy-DibiProfiler-sql { background: white !important }
#tracy-debug .tracy-DibiProfiler-source { color: #999 !important }
#tracy-debug tracy-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
<h1>Queries: ' . count($this->events) . ($totalTime === NULL ? '' : sprintf(', time: %0.3f ms', $totalTime * 1000)) . '</h1>
<div class="tracy-inner tracy-DibiProfiler">
<table>
<tr><th>Time&nbsp;ms</th><th>SQL Statement</th><th>Rows</th><th>Connection</th></tr>' . $s . '
</table>
</div>';
}
}

View File

@@ -1,39 +1,416 @@
<?php
/**
* dibi - smart database abstraction layer (http://dibiphp.com)
*
* Copyright (c) 2005, 2012 David Grudl (https://davidgrudl.com)
*/
/**
* Check PHP configuration.
*/
if (version_compare(PHP_VERSION, '5.2.0', '<')) {
throw new Exception('dibi needs PHP 5.2.0 or newer.');
}
require_once dirname(__FILE__) . '/libs/interfaces.php';
require_once dirname(__FILE__) . '/libs/Dibi.php';
require_once dirname(__FILE__) . '/libs/DibiDateTime.php';
require_once dirname(__FILE__) . '/libs/DibiObject.php';
require_once dirname(__FILE__) . '/libs/DibiLiteral.php';
require_once dirname(__FILE__) . '/libs/DibiHashMap.php';
require_once dirname(__FILE__) . '/libs/DibiException.php';
require_once dirname(__FILE__) . '/libs/DibiConnection.php';
require_once dirname(__FILE__) . '/libs/DibiResult.php';
require_once dirname(__FILE__) . '/libs/DibiResultIterator.php';
require_once dirname(__FILE__) . '/libs/DibiRow.php';
require_once dirname(__FILE__) . '/libs/DibiTranslator.php';
require_once dirname(__FILE__) . '/libs/DibiDataSource.php';
require_once dirname(__FILE__) . '/libs/DibiFluent.php';
require_once dirname(__FILE__) . '/libs/DibiDatabaseInfo.php';
require_once dirname(__FILE__) . '/libs/DibiEvent.php';
require_once dirname(__FILE__) . '/libs/DibiFileLogger.php';
require_once dirname(__FILE__) . '/libs/DibiFirePhpLogger.php';
if (interface_exists('Nette\Diagnostics\IBarPanel') || interface_exists('IBarPanel')) {
require_once dirname(__FILE__) . '/bridges/Nette-2.1/DibiNettePanel.php';
}
<?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.5b (2006-05-31) 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
?>

View File

@@ -1,842 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi driver for Firebird/InterBase database.
*
* Driver options:
* - database => the path to database file (server:/path/database.fdb)
* - username (or user)
* - password (or pass)
* - charset => character encoding to set
* - buffers (int) => buffers is the number of database buffers to allocate for the server-side cache. If 0 or omitted, server chooses its own default.
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author Tomáš Kraina, Roman Sklenář
* @package dibi\drivers
*/
class DibiFirebirdDriver extends DibiObject implements IDibiDriver, IDibiResultDriver, IDibiReflector
{
const ERROR_EXCEPTION_THROWN = -836;
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var resource Resultset resource */
private $transaction;
/** @var bool */
private $inTransaction = FALSE;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('interbase')) {
throw new DibiNotSupportedException("PHP extension 'interbase' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
DibiConnection::alias($config, 'database', 'db');
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// default values
$config += array(
'username' => ini_get('ibase.default_password'),
'password' => ini_get('ibase.default_user'),
'database' => ini_get('ibase.default_db'),
'charset' => ini_get('ibase.default_charset'),
'buffers' => 0,
);
DibiDriverException::tryError();
if (empty($config['persistent'])) {
$this->connection = ibase_connect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
} else {
$this->connection = ibase_pconnect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
}
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, ibase_errcode());
}
if (!is_resource($this->connection)) {
throw new DibiDriverException(ibase_errmsg(), ibase_errcode());
}
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
ibase_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException|DibiException
*/
public function query($sql)
{
DibiDriverException::tryError();
$resource = $this->inTransaction ? $this->transaction : $this->connection;
$res = ibase_query($resource, $sql);
if (DibiDriverException::catchError($msg)) {
if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
preg_match('/exception (\d+) (\w+) (.*)/i', ibase_errmsg(), $match);
throw new DibiProcedureException($match[3], $match[1], $match[2], dibi::$sql);
} else {
throw new DibiDriverException(ibase_errmsg(), ibase_errcode(), dibi::$sql);
}
}
if ($res === FALSE) {
throw new DibiDriverException(ibase_errmsg(), ibase_errcode(), $sql);
} elseif (is_resource($res)) {
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return ibase_affected_rows($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @param string generator name
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return ibase_gen_id($sequence, 0, $this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
if ($savepoint !== NULL) {
throw new DibiNotSupportedException('Savepoints are not supported in Firebird/Interbase.');
}
$this->transaction = ibase_trans($this->resource);
$this->inTransaction = TRUE;
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if ($savepoint !== NULL) {
throw new DibiNotSupportedException('Savepoints are not supported in Firebird/Interbase.');
}
if (!ibase_commit($this->transaction)) {
throw new DibiDriverException('Unable to handle operation - failure when commiting transaction.');
}
$this->inTransaction = FALSE;
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if ($savepoint !== NULL) {
throw new DibiNotSupportedException('Savepoints are not supported in Firebird/Interbase.');
}
if (!ibase_rollback($this->transaction)) {
throw new DibiDriverException('Unable to handle operation - failure when rolbacking transaction.');
}
$this->inTransaction = FALSE;
}
/**
* Is in transaction?
* @return bool
*/
public function inTransaction()
{
return $this->inTransaction;
}
/**
* Returns the connection resource.
* @return resource
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return $this;
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ********************/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
return $value;
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
throw new DibiNotImplementedException;
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 && $offset > 0) {
// see http://scott.yang.id.au/2004/01/limit-in-select-statements-in-firebird/
$sql = 'SELECT FIRST ' . (int) $limit . ($offset > 0 ? ' SKIP ' . (int) $offset : '') . ' * FROM (' . $sql . ')';
}
}
/********************* result set ********************/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
throw new DibiNotSupportedException('Firebird/Interbase do not support returning number of rows in result set.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
DibiDriverException::tryError();
$result = $assoc ? ibase_fetch_assoc($this->resultSet, IBASE_TEXT) : ibase_fetch_row($this->resultSet, IBASE_TEXT); // intentionally @
if (DibiDriverException::catchError($msg)) {
if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
preg_match('/exception (\d+) (\w+) (.*)/is', ibase_errmsg(), $match);
throw new DibiProcedureException($match[3], $match[1], $match[2], dibi::$sql);
} else {
throw new DibiDriverException($msg, ibase_errcode(), dibi::$sql);
}
}
return $result;
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
throw new DibiNotSupportedException('Firebird/Interbase do not support seek in result set.');
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
ibase_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns the result set resource.
* @return mysqli_result
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = ibase_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) ibase_field_info($this->resultSet, $i);
$columns[] = array(
'name' => $row['name'],
'fullname' => $row['name'],
'table' => $row['relation'],
'nativetype' => $row['type'],
);
}
return $columns;
}
/********************* IDibiReflector ********************/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->query("
SELECT TRIM(RDB\$RELATION_NAME),
CASE RDB\$VIEW_BLR WHEN NULL THEN 'TRUE' ELSE 'FALSE' END
FROM RDB\$RELATIONS
WHERE RDB\$SYSTEM_FLAG = 0;"
);
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => $row[1] === 'TRUE',
);
}
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$table = strtoupper($table);
$res = $this->query("
SELECT TRIM(r.RDB\$FIELD_NAME) AS FIELD_NAME,
CASE f.RDB\$FIELD_TYPE
WHEN 261 THEN 'BLOB'
WHEN 14 THEN 'CHAR'
WHEN 40 THEN 'CSTRING'
WHEN 11 THEN 'D_FLOAT'
WHEN 27 THEN 'DOUBLE'
WHEN 10 THEN 'FLOAT'
WHEN 16 THEN 'INT64'
WHEN 8 THEN 'INTEGER'
WHEN 9 THEN 'QUAD'
WHEN 7 THEN 'SMALLINT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN 'VARCHAR'
ELSE 'UNKNOWN'
END AS FIELD_TYPE,
f.RDB\$FIELD_LENGTH AS FIELD_LENGTH,
r.RDB\$DEFAULT_VALUE AS DEFAULT_VALUE,
CASE r.RDB\$NULL_FLAG
WHEN 1 THEN 'FALSE' ELSE 'TRUE'
END AS NULLABLE
FROM RDB\$RELATION_FIELDS r
LEFT JOIN RDB\$FIELDS f ON r.RDB\$FIELD_SOURCE = f.RDB\$FIELD_NAME
WHERE r.RDB\$RELATION_NAME = '$table'
ORDER BY r.RDB\$FIELD_POSITION;"
);
$columns = array();
while ($row = $res->fetch(TRUE)) {
$key = $row['FIELD_NAME'];
$columns[$key] = array(
'name' => $key,
'table' => $table,
'nativetype' => trim($row['FIELD_TYPE']),
'size' => $row['FIELD_LENGTH'],
'nullable' => $row['NULLABLE'] === 'TRUE',
'default' => $row['DEFAULT_VALUE'],
'autoincrement' => FALSE,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table (the constraints are included).
* @param string
* @return array
*/
public function getIndexes($table)
{
$table = strtoupper($table);
$res = $this->query("
SELECT TRIM(s.RDB\$INDEX_NAME) AS INDEX_NAME,
TRIM(s.RDB\$FIELD_NAME) AS FIELD_NAME,
i.RDB\$UNIQUE_FLAG AS UNIQUE_FLAG,
i.RDB\$FOREIGN_KEY AS FOREIGN_KEY,
TRIM(r.RDB\$CONSTRAINT_TYPE) AS CONSTRAINT_TYPE,
s.RDB\$FIELD_POSITION AS FIELD_POSITION
FROM RDB\$INDEX_SEGMENTS s
LEFT JOIN RDB\$INDICES i ON i.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
LEFT JOIN RDB\$RELATION_CONSTRAINTS r ON r.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
WHERE UPPER(i.RDB\$RELATION_NAME) = '$table'
ORDER BY s.RDB\$FIELD_POSITION"
);
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$key = $row['INDEX_NAME'];
$indexes[$key]['name'] = $key;
$indexes[$key]['unique'] = $row['UNIQUE_FLAG'] === 1;
$indexes[$key]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
$indexes[$key]['table'] = $table;
$indexes[$key]['columns'][$row['FIELD_POSITION']] = $row['FIELD_NAME'];
}
return $indexes;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$table = strtoupper($table);
$res = $this->query("
SELECT TRIM(s.RDB\$INDEX_NAME) AS INDEX_NAME,
TRIM(s.RDB\$FIELD_NAME) AS FIELD_NAME,
FROM RDB\$INDEX_SEGMENTS s
LEFT JOIN RDB\$RELATION_CONSTRAINTS r ON r.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
WHERE UPPER(i.RDB\$RELATION_NAME) = '$table'
AND r.RDB\$CONSTRAINT_TYPE = 'FOREIGN KEY'
ORDER BY s.RDB\$FIELD_POSITION"
);
$keys = array();
while ($row = $res->fetch(TRUE)) {
$key = $row['INDEX_NAME'];
$keys[$key] = array(
'name' => $key,
'column' => $row['FIELD_NAME'],
'table' => $table,
);
}
return $keys;
}
/**
* Returns list of indices in given table (the constraints are not listed).
* @param string
* @return array
*/
public function getIndices($table)
{
$res = $this->query("
SELECT TRIM(RDB\$INDEX_NAME)
FROM RDB\$INDICES
WHERE RDB\$RELATION_NAME = UPPER('$table')
AND RDB\$UNIQUE_FLAG IS NULL
AND RDB\$FOREIGN_KEY IS NULL;"
);
$indices = array();
while ($row = $res->fetch(FALSE)) {
$indices[] = $row[0];
}
return $indices;
}
/**
* Returns list of constraints in given table.
* @param string
* @return array
*/
public function getConstraints($table)
{
$res = $this->query("
SELECT TRIM(RDB\$INDEX_NAME)
FROM RDB\$INDICES
WHERE RDB\$RELATION_NAME = UPPER('$table')
AND (
RDB\$UNIQUE_FLAG IS NOT NULL
OR RDB\$FOREIGN_KEY IS NOT NULL
);"
);
$constraints = array();
while ($row = $res->fetch(FALSE)) {
$constraints[] = $row[0];
}
return $constraints;
}
/**
* Returns metadata for all triggers in a table or database.
* (Only if user has permissions on ALTER TABLE, INSERT/UPDATE/DELETE record in table)
* @param string
* @param string
* @return array
*/
public function getTriggersMeta($table = NULL)
{
$res = $this->query("
SELECT TRIM(RDB\$TRIGGER_NAME) AS TRIGGER_NAME,
TRIM(RDB\$RELATION_NAME) AS TABLE_NAME,
CASE RDB\$TRIGGER_TYPE
WHEN 1 THEN 'BEFORE'
WHEN 2 THEN 'AFTER'
WHEN 3 THEN 'BEFORE'
WHEN 4 THEN 'AFTER'
WHEN 5 THEN 'BEFORE'
WHEN 6 THEN 'AFTER'
END AS TRIGGER_TYPE,
CASE RDB\$TRIGGER_TYPE
WHEN 1 THEN 'INSERT'
WHEN 2 THEN 'INSERT'
WHEN 3 THEN 'UPDATE'
WHEN 4 THEN 'UPDATE'
WHEN 5 THEN 'DELETE'
WHEN 6 THEN 'DELETE'
END AS TRIGGER_EVENT,
CASE RDB\$TRIGGER_INACTIVE
WHEN 1 THEN 'FALSE' ELSE 'TRUE'
END AS TRIGGER_ENABLED
FROM RDB\$TRIGGERS
WHERE RDB\$SYSTEM_FLAG = 0"
. ($table === NULL ? ';' : " AND RDB\$RELATION_NAME = UPPER('$table');")
);
$triggers = array();
while ($row = $res->fetch(TRUE)) {
$triggers[$row['TRIGGER_NAME']] = array(
'name' => $row['TRIGGER_NAME'],
'table' => $row['TABLE_NAME'],
'type' => trim($row['TRIGGER_TYPE']),
'event' => trim($row['TRIGGER_EVENT']),
'enabled' => trim($row['TRIGGER_ENABLED']) === 'TRUE',
);
}
return $triggers;
}
/**
* Returns list of triggers for given table.
* (Only if user has permissions on ALTER TABLE, INSERT/UPDATE/DELETE record in table)
* @param string
* @return array
*/
public function getTriggers($table = NULL)
{
$q = "SELECT TRIM(RDB\$TRIGGER_NAME)
FROM RDB\$TRIGGERS
WHERE RDB\$SYSTEM_FLAG = 0";
$q .= $table === NULL ? ';' : " AND RDB\$RELATION_NAME = UPPER('$table')";
$res = $this->query($q);
$triggers = array();
while ($row = $res->fetch(FALSE)) {
$triggers[] = $row[0];
}
return $triggers;
}
/**
* Returns metadata from stored procedures and their input and output parameters.
* @param string
* @return array
*/
public function getProceduresMeta()
{
$res = $this->query("
SELECT
TRIM(p.RDB\$PARAMETER_NAME) AS PARAMETER_NAME,
TRIM(p.RDB\$PROCEDURE_NAME) AS PROCEDURE_NAME,
CASE p.RDB\$PARAMETER_TYPE
WHEN 0 THEN 'INPUT'
WHEN 1 THEN 'OUTPUT'
ELSE 'UNKNOWN'
END AS PARAMETER_TYPE,
CASE f.RDB\$FIELD_TYPE
WHEN 261 THEN 'BLOB'
WHEN 14 THEN 'CHAR'
WHEN 40 THEN 'CSTRING'
WHEN 11 THEN 'D_FLOAT'
WHEN 27 THEN 'DOUBLE'
WHEN 10 THEN 'FLOAT'
WHEN 16 THEN 'INT64'
WHEN 8 THEN 'INTEGER'
WHEN 9 THEN 'QUAD'
WHEN 7 THEN 'SMALLINT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN 'VARCHAR'
ELSE 'UNKNOWN'
END AS FIELD_TYPE,
f.RDB\$FIELD_LENGTH AS FIELD_LENGTH,
p.RDB\$PARAMETER_NUMBER AS PARAMETER_NUMBER
FROM RDB\$PROCEDURE_PARAMETERS p
LEFT JOIN RDB\$FIELDS f ON f.RDB\$FIELD_NAME = p.RDB\$FIELD_SOURCE
ORDER BY p.RDB\$PARAMETER_TYPE, p.RDB\$PARAMETER_NUMBER;"
);
$procedures = array();
while ($row = $res->fetch(TRUE)) {
$key = $row['PROCEDURE_NAME'];
$io = trim($row['PARAMETER_TYPE']);
$num = $row['PARAMETER_NUMBER'];
$procedures[$key]['name'] = $row['PROCEDURE_NAME'];
$procedures[$key]['params'][$io][$num]['name'] = $row['PARAMETER_NAME'];
$procedures[$key]['params'][$io][$num]['type'] = trim($row['FIELD_TYPE']);
$procedures[$key]['params'][$io][$num]['size'] = $row['FIELD_LENGTH'];
}
return $procedures;
}
/**
* Returns list of stored procedures.
* @return array
*/
public function getProcedures()
{
$res = $this->query("
SELECT TRIM(RDB\$PROCEDURE_NAME)
FROM RDB\$PROCEDURES;"
);
$procedures = array();
while ($row = $res->fetch(FALSE)) {
$procedures[] = $row[0];
}
return $procedures;
}
/**
* Returns list of generators.
* @return array
*/
public function getGenerators()
{
$res = $this->query("
SELECT TRIM(RDB\$GENERATOR_NAME)
FROM RDB\$GENERATORS
WHERE RDB\$SYSTEM_FLAG = 0;"
);
$generators = array();
while ($row = $res->fetch(FALSE)) {
$generators[] = $row[0];
}
return $generators;
}
/**
* Returns list of user defined functions (UDF).
* @return array
*/
public function getFunctions()
{
$res = $this->query("
SELECT TRIM(RDB\$FUNCTION_NAME)
FROM RDB\$FUNCTIONS
WHERE RDB\$SYSTEM_FLAG = 0;"
);
$functions = array();
while ($row = $res->fetch(FALSE)) {
$functions[] = $row[0];
}
return $functions;
}
}
/**
* Database procedure exception.
*
* @author Roman Sklenář
* @copyright Copyright (c) 2010
* @package dibi\drivers
*/
class DibiProcedureException extends DibiException
{
/** @var string */
protected $severity;
/**
* Construct the exception.
* @param string Message describing the exception
* @param int Some code
* @param string SQL command
*/
public function __construct($message = NULL, $code = 0, $severity = NULL, $sql = NULL)
{
parent::__construct($message, (int) $code, $sql);
$this->severity = $severity;
}
/**
* Gets the exception severity.
* @return string
*/
public function getSeverity()
{
$this->severity;
}
}

View File

@@ -1,378 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiMsSql2005Reflector.php';
/**
* The dibi driver for MS SQL Driver 2005 database.
*
* Driver options:
* - host => the MS SQL server host name. It can also include a port number (hostname:port)
* - username (or user)
* - password (or pass)
* - database => the database name to select
* - options (array) => connection options {@link https://msdn.microsoft.com/en-us/library/cc296161(SQL.90).aspx}
* - charset => character encoding to set (default is UTF-8)
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var int|FALSE Affected rows */
private $affectedRows = FALSE;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('sqlsrv')) {
throw new DibiNotSupportedException("PHP extension 'sqlsrv' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
DibiConnection::alias($config, 'options|UID', 'username');
DibiConnection::alias($config, 'options|PWD', 'password');
DibiConnection::alias($config, 'options|Database', 'database');
DibiConnection::alias($config, 'options|CharacterSet', 'charset');
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// Default values
if (!isset($config['options']['CharacterSet'])) {
$config['options']['CharacterSet'] = 'UTF-8';
}
$this->connection = sqlsrv_connect($config['host'], (array) $config['options']);
}
if (!is_resource($this->connection)) {
$info = sqlsrv_errors();
throw new DibiDriverException($info[0]['message'], $info[0]['code']);
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
sqlsrv_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->affectedRows = FALSE;
$res = sqlsrv_query($this->connection, $sql);
if ($res === FALSE) {
$info = sqlsrv_errors();
throw new DibiDriverException($info[0]['message'], $info[0]['code'], $sql);
} elseif (is_resource($res)) {
$this->affectedRows = sqlsrv_rows_affected($res);
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return $this->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
*/
public function getInsertId($sequence)
{
$res = sqlsrv_query($this->connection, 'SELECT @@IDENTITY');
if (is_resource($res)) {
$row = sqlsrv_fetch_array($res, SQLSRV_FETCH_NUMERIC);
return $row[0];
}
return FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
sqlsrv_begin_transaction($this->connection);
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
sqlsrv_commit($this->connection);
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
sqlsrv_rollback($this->connection);
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return new DibiMssql2005Reflector($this);
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
return '[' . str_replace(']', ']]', $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') AS T ';
}
if ($offset) {
throw new DibiNotImplementedException('Offset is not implemented.');
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
throw new DibiNotSupportedException('Row count is not available for unbuffered queries.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return sqlsrv_fetch_array($this->resultSet, $assoc ? SQLSRV_FETCH_ASSOC : SQLSRV_FETCH_NUMERIC);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
throw new DibiNotSupportedException('Cannot seek an unbuffered result set.');
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
sqlsrv_free_stmt($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$columns = array();
foreach ((array) sqlsrv_field_metadata($this->resultSet) as $fieldMetadata) {
$columns[] = array(
'name' => $fieldMetadata['Name'],
'fullname' => $fieldMetadata['Name'],
'nativetype' => $fieldMetadata['Type'],
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
}

View File

@@ -1,133 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi reflector for MSSQL2005 databases.
*
* @author Daniel Kouba
* @package dibi\drivers
* @internal
*/
class DibiMsSql2005Reflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query('SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES');
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = $this->driver->query("
SELECT c.name as COLUMN_NAME, c.is_identity AS AUTO_INCREMENT
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = {$this->driver->escape($table, dibi::TEXT)}
");
$autoIncrements = array();
while ($row = $res->fetch(TRUE)) {
$autoIncrements[$row['COLUMN_NAME']] = (bool) $row['AUTO_INCREMENT'];
}
$res = $this->driver->query("
SELECT C.COLUMN_NAME, C.DATA_TYPE, C.CHARACTER_MAXIMUM_LENGTH , C.COLUMN_DEFAULT , C.NUMERIC_PRECISION, C.NUMERIC_SCALE , C.IS_NULLABLE, Case When Z.CONSTRAINT_NAME Is Null Then 0 Else 1 End As IsPartOfPrimaryKey
FROM INFORMATION_SCHEMA.COLUMNS As C
Outer Apply (
SELECT CCU.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS As TC
Join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE As CCU
On CCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
WHERE TC.TABLE_SCHEMA = C.TABLE_SCHEMA
And TC.TABLE_NAME = C.TABLE_NAME
And TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
And CCU.COLUMN_NAME = C.COLUMN_NAME
) As Z
WHERE C.TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}
");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$columns[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => strtoupper($row['DATA_TYPE']),
'size' => $row['CHARACTER_MAXIMUM_LENGTH'],
'unsigned' => TRUE,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
'autoincrement' => $autoIncrements[$row['COLUMN_NAME']],
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$keyUsagesRes = $this->driver->query("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}");
$keyUsages = array();
while ($row = $keyUsagesRes->fetch(TRUE)) {
$keyUsages[$row['CONSTRAINT_NAME']][(int) $row['ORDINAL_POSITION'] - 1] = $row['COLUMN_NAME'];
}
$res = $this->driver->query("SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['CONSTRAINT_NAME']]['name'] = $row['CONSTRAINT_NAME'];
$indexes[$row['CONSTRAINT_NAME']]['unique'] = $row['CONSTRAINT_TYPE'] === 'UNIQUE';
$indexes[$row['CONSTRAINT_NAME']]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
$indexes[$row['CONSTRAINT_NAME']]['columns'] = isset($keyUsages[$row['CONSTRAINT_NAME']]) ? $keyUsages[$row['CONSTRAINT_NAME']] : array();
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new DibiNotImplementedException;
}
}

View File

@@ -1,366 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiMsSqlReflector.php';
/**
* The dibi driver for MS SQL database.
*
* Driver options:
* - host => the MS SQL server host name. It can also include a port number (hostname:port)
* - username (or user)
* - password (or pass)
* - database => the database name to select
* - persistent (bool) => try to find a persistent link?
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiMsSqlDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('mssql')) {
throw new DibiNotSupportedException("PHP extension 'mssql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (empty($config['persistent'])) {
$this->connection = @mssql_connect($config['host'], $config['username'], $config['password'], TRUE); // intentionally @
} else {
$this->connection = @mssql_pconnect($config['host'], $config['username'], $config['password']); // intentionally @
}
if (!is_resource($this->connection)) {
throw new DibiDriverException("Can't connect to DB.");
}
if (isset($config['database']) && !@mssql_select_db($this->escape($config['database'], dibi::IDENTIFIER), $this->connection)) { // intentionally @
throw new DibiDriverException("Can't select DB '$config[database]'.");
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
mssql_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$res = @mssql_query($sql, $this->connection); // intentionally @
if ($res === FALSE) {
throw new DibiDriverException(mssql_get_last_message(), 0, $sql);
} elseif (is_resource($res)) {
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mssql_rows_affected($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
$res = mssql_query('SELECT @@IDENTITY', $this->connection);
if (is_resource($res)) {
$row = mssql_fetch_row($res);
return $row[0];
}
return FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query('BEGIN TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query('COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query('ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return new DibiMsSqlReflector($this);
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t';
}
if ($offset) {
throw new DibiNotImplementedException('Offset is not implemented.');
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return mssql_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return mssql_fetch_array($this->resultSet, $assoc ? MSSQL_ASSOC : MSSQL_NUM);
}
/**
* 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
*/
public function seek($row)
{
return mssql_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mssql_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = mssql_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) mssql_fetch_field($this->resultSet, $i);
$columns[] = array(
'name' => $row['name'],
'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'],
'table' => $row['column_source'],
'nativetype' => $row['type'],
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
}

View File

@@ -1,216 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005, 2010 David Grudl (https://davidgrudl.com)
*
* @package dibi\drivers
*/
/**
* The dibi reflector for MsSQL databases.
*
* @author Steven Bredenberg
* @package dibi\drivers
* @internal
*/
class DibiMsSqlReflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query('
SELECT TABLE_NAME, TABLE_TYPE
FROM INFORMATION_SCHEMA.TABLES
');
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
return $tables;
}
/**
* Returns count of rows in a table
* @param string
* @return int
*/
public function getTableCount($table, $fallback = TRUE)
{
if (empty($table)) {
return FALSE;
}
$result = $this->driver->query("
SELECT MAX(rowcnt)
FROM sys.sysindexes
WHERE id=OBJECT_ID({$this->driver->escape($table, dibi::IDENTIFIER)})
");
$row = $result->fetch(FALSE);
if (!is_array($row) || count($row) < 1) {
if ($fallback) {
$row = $this->driver->query("SELECT COUNT(*) FROM {$this->driver->escape($table, dibi::IDENTIFIER)}")->fetch(FALSE);
$count = intval($row[0]);
} else {
$count = FALSE;
}
} else {
$count = intval($row[0]);
}
return $count;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = $this->driver->query("
SELECT * FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}
ORDER BY TABLE_NAME, ORDINAL_POSITION
");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$size = FALSE;
$type = strtoupper($row['DATA_TYPE']);
$size_cols = array(
'DATETIME' => 'DATETIME_PRECISION',
'DECIMAL' => 'NUMERIC_PRECISION',
'CHAR' => 'CHARACTER_MAXIMUM_LENGTH',
'NCHAR' => 'CHARACTER_OCTET_LENGTH',
'NVARCHAR' => 'CHARACTER_OCTET_LENGTH',
'VARCHAR' => 'CHARACTER_OCTET_LENGTH',
);
if (isset($size_cols[$type])) {
if ($size_cols[$type]) {
$size = $row[$size_cols[$type]];
}
}
$columns[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => $type,
'size' => $size,
'unsigned' => NULL,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
'autoincrement' => FALSE,
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$res = $this->driver->query(
"SELECT ind.name index_name, ind.index_id, ic.index_column_id,
col.name column_name, ind.is_unique, ind.is_primary_key
FROM sys.indexes ind
INNER JOIN sys.index_columns ic ON
(ind.object_id = ic.object_id AND ind.index_id = ic.index_id)
INNER JOIN sys.columns col ON
(ic.object_id = col.object_id and ic.column_id = col.column_id)
INNER JOIN sys.tables t ON
(ind.object_id = t.object_id)
WHERE t.name = {$this->driver->escape($table, dibi::TEXT)}
AND t.is_ms_shipped = 0
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id
");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$index_name = $row['index_name'];
if (!isset($indexes[$index_name])) {
$indexes[$index_name] = array();
$indexes[$index_name]['name'] = $index_name;
$indexes[$index_name]['unique'] = (bool) $row['is_unique'];
$indexes[$index_name]['primary'] = (bool) $row['is_primary_key'];
$indexes[$index_name]['columns'] = array();
}
$indexes[$index_name]['columns'][] = $row['column_name'];
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$res = $this->driver->query("
SELECT f.name AS foreign_key,
OBJECT_NAME(f.parent_object_id) AS table_name,
COL_NAME(fc.parent_object_id,
fc.parent_column_id) AS column_name,
OBJECT_NAME (f.referenced_object_id) AS reference_table_name,
COL_NAME(fc.referenced_object_id,
fc.referenced_column_id) AS reference_column_name,
fc.*
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
WHERE OBJECT_NAME(f.parent_object_id) = {$this->driver->escape($table, dibi::TEXT)}
");
$keys = array();
while ($row = $res->fetch(TRUE)) {
$key_name = $row['foreign_key'];
if (!isset($keys[$key_name])) {
$keys[$key_name]['name'] = $row['foreign_key']; // foreign key name
$keys[$key_name]['local'] = array($row['column_name']); // local columns
$keys[$key_name]['table'] = $row['reference_table_name']; // referenced table
$keys[$key_name]['foreign'] = array($row['reference_column_name']); // referenced columns
$keys[$key_name]['onDelete'] = FALSE;
$keys[$key_name]['onUpdate'] = FALSE;
} else {
$keys[$key_name]['local'][] = $row['column_name']; // local columns
$keys[$key_name]['foreign'][] = $row['reference_column_name']; // referenced columns
}
}
return array_values($keys);
}
}

View File

@@ -1,466 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
/**
* The dibi driver for MySQL database.
*
* Driver options:
* - host => the MySQL server host name
* - port (int) => the port number to attempt to connect to the MySQL server
* - socket => the socket or named pipe
* - username (or user)
* - password (or pass)
* - database => the database name to select
* - flags (int) => driver specific constants (MYSQL_CLIENT_*)
* - charset => character encoding to set (default is utf8)
* - persistent (bool) => try to find a persistent link?
* - unbuffered (bool) => sends query without fetching and buffering the result rows automatically?
* - sqlmode => see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiMySqlDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
const ERROR_ACCESS_DENIED = 1045;
const ERROR_DUPLICATE_ENTRY = 1062;
const ERROR_DATA_TRUNCATED = 1265;
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var bool Is buffered (seekable and countable)? */
private $buffered;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('mysql')) {
throw new DibiNotSupportedException("PHP extension 'mysql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// default values
DibiConnection::alias($config, 'flags', 'options');
$config += array(
'charset' => 'utf8',
'timezone' => date('P'),
'username' => ini_get('mysql.default_user'),
'password' => ini_get('mysql.default_password'),
);
if (!isset($config['host'])) {
$host = ini_get('mysql.default_host');
if ($host) {
$config['host'] = $host;
$config['port'] = ini_get('mysql.default_port');
} else {
if (!isset($config['socket'])) {
$config['socket'] = ini_get('mysql.default_socket');
}
$config['host'] = NULL;
}
}
if (empty($config['socket'])) {
$host = $config['host'] . (empty($config['port']) ? '' : ':' . $config['port']);
} else {
$host = ':' . $config['socket'];
}
if (empty($config['persistent'])) {
$this->connection = @mysql_connect($host, $config['username'], $config['password'], TRUE, $config['flags']); // intentionally @
} else {
$this->connection = @mysql_pconnect($host, $config['username'], $config['password'], $config['flags']); // intentionally @
}
}
if (!is_resource($this->connection)) {
throw new DibiDriverException(mysql_error(), mysql_errno());
}
if (isset($config['charset'])) {
$ok = FALSE;
if (function_exists('mysql_set_charset')) {
// affects the character set used by mysql_real_escape_string() (was added in MySQL 5.0.7 and PHP 5.2.3)
$ok = @mysql_set_charset($config['charset'], $this->connection); // intentionally @
}
if (!$ok) {
$this->query("SET NAMES '$config[charset]'");
}
}
if (isset($config['database'])) {
if (!@mysql_select_db($config['database'], $this->connection)) { // intentionally @
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection));
}
}
if (isset($config['sqlmode'])) {
$this->query("SET sql_mode='$config[sqlmode]'");
}
if (isset($config['timezone'])) {
$this->query("SET time_zone='$config[timezone]'");
}
$this->buffered = empty($config['unbuffered']);
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
mysql_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
if ($this->buffered) {
$res = @mysql_query($sql, $this->connection); // intentionally @
} else {
$res = @mysql_unbuffered_query($sql, $this->connection); // intentionally @
}
if (mysql_errno($this->connection)) {
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection), $sql);
} elseif (is_resource($res)) {
return $this->createResultDriver($res);
}
}
/**
* Retrieves information about the most recently executed query.
* @return array
*/
public function getInfo()
{
$res = array();
preg_match_all('#(.+?): +(\d+) *#', mysql_info($this->connection), $matches, PREG_SET_ORDER);
if (preg_last_error()) {
throw new DibiPcreException;
}
foreach ($matches as $m) {
$res[$m[1]] = (int) $m[2];
}
return $res;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mysql_affected_rows($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return mysql_insert_id($this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return new DibiMySqlReflector($this);
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
if (!is_resource($this->connection)) {
throw new DibiException('Lost connection to server.');
}
return "'" . mysql_real_escape_string($value, $this->connection) . "'";
case dibi::BINARY:
if (!is_resource($this->connection)) {
throw new DibiException('Lost connection to server.');
}
return "_binary'" . mysql_real_escape_string($value, $this->connection) . "'";
case dibi::IDENTIFIER:
// @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
return '`' . str_replace('`', '``', $value) . '`';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 || $offset > 0) {
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
if (!$this->buffered) {
throw new DibiNotSupportedException('Row count is not available for unbuffered queries.');
}
return mysql_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return mysql_fetch_array($this->resultSet, $assoc ? MYSQL_ASSOC : MYSQL_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
if (!$this->buffered) {
throw new DibiNotSupportedException('Cannot seek an unbuffered result set.');
}
return mysql_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mysql_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = mysql_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) mysql_fetch_field($this->resultSet, $i);
$columns[] = array(
'name' => $row['name'],
'table' => $row['table'],
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
'nativetype' => strtoupper($row['type']),
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
}

View File

@@ -1,150 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi reflector for MySQL databases.
*
* @author David Grudl
* @package dibi\drivers
* @internal
*/
class DibiMySqlReflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
/*$this->query("
SELECT TABLE_NAME as name, TABLE_TYPE = 'VIEW' as view
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
");*/
$res = $this->driver->query('SHOW FULL TABLES');
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
/*$table = $this->escape($table, dibi::TEXT);
$this->query("
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
");*/
$res = $this->driver->query("SHOW FULL COLUMNS FROM {$this->driver->escape($table, dibi::IDENTIFIER)}");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$type = explode('(', $row['Type']);
$columns[] = array(
'name' => $row['Field'],
'table' => $table,
'nativetype' => strtoupper($type[0]),
'size' => isset($type[1]) ? (int) $type[1] : NULL,
'unsigned' => (bool) strstr($row['Type'], 'unsigned'),
'nullable' => $row['Null'] === 'YES',
'default' => $row['Default'],
'autoincrement' => $row['Extra'] === 'auto_increment',
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
/*$table = $this->escape($table, dibi::TEXT);
$this->query("
SELECT *
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
AND REFERENCED_COLUMN_NAME IS NULL
");*/
$res = $this->driver->query("SHOW INDEX FROM {$this->driver->escape($table, dibi::IDENTIFIER)}");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['Key_name']]['name'] = $row['Key_name'];
$indexes[$row['Key_name']]['unique'] = !$row['Non_unique'];
$indexes[$row['Key_name']]['primary'] = $row['Key_name'] === 'PRIMARY';
$indexes[$row['Key_name']]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
* @throws DibiNotSupportedException
*/
public function getForeignKeys($table)
{
$data = $this->driver->query("SELECT `ENGINE` FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}")->fetch(TRUE);
if ($data['ENGINE'] !== 'InnoDB') {
throw new DibiNotSupportedException("Foreign keys are not supported in {$data['ENGINE']} tables.");
}
$res = $this->driver->query("
SELECT rc.CONSTRAINT_NAME, rc.UPDATE_RULE, rc.DELETE_RULE, kcu.REFERENCED_TABLE_NAME,
GROUP_CONCAT(kcu.REFERENCED_COLUMN_NAME ORDER BY kcu.ORDINAL_POSITION) AS REFERENCED_COLUMNS,
GROUP_CONCAT(kcu.COLUMN_NAME ORDER BY kcu.ORDINAL_POSITION) AS COLUMNS
FROM information_schema.REFERENTIAL_CONSTRAINTS rc
INNER JOIN information_schema.KEY_COLUMN_USAGE kcu ON
kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
AND kcu.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
WHERE rc.CONSTRAINT_SCHEMA = DATABASE()
AND rc.TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}
GROUP BY rc.CONSTRAINT_NAME
");
$foreignKeys = array();
while ($row = $res->fetch(TRUE)) {
$keyName = $row['CONSTRAINT_NAME'];
$foreignKeys[$keyName]['name'] = $keyName;
$foreignKeys[$keyName]['local'] = explode(',', $row['COLUMNS']);
$foreignKeys[$keyName]['table'] = $row['REFERENCED_TABLE_NAME'];
$foreignKeys[$keyName]['foreign'] = explode(',', $row['REFERENCED_COLUMNS']);
$foreignKeys[$keyName]['onDelete'] = $row['DELETE_RULE'];
$foreignKeys[$keyName]['onUpdate'] = $row['UPDATE_RULE'];
}
return array_values($foreignKeys);
}
}

View File

@@ -1,459 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
/**
* The dibi driver for MySQL database via improved extension.
*
* Driver options:
* - host => the MySQL server host name
* - port (int) => the port number to attempt to connect to the MySQL server
* - socket => the socket or named pipe
* - username (or user)
* - password (or pass)
* - database => the database name to select
* - options (array) => array of driver specific constants (MYSQLI_*) and values {@see mysqli_options}
* - flags (int) => driver specific constants (MYSQLI_CLIENT_*) {@see mysqli_real_connect}
* - charset => character encoding to set (default is utf8)
* - persistent (bool) => try to find a persistent link?
* - unbuffered (bool) => sends query without fetching and buffering the result rows automatically?
* - sqlmode => see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
* - resource (mysqli) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiMySqliDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
const ERROR_ACCESS_DENIED = 1045;
const ERROR_DUPLICATE_ENTRY = 1062;
const ERROR_DATA_TRUNCATED = 1265;
/** @var mysqli Connection resource */
private $connection;
/** @var mysqli_result Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var bool Is buffered (seekable and countable)? */
private $buffered;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('mysqli')) {
throw new DibiNotSupportedException("PHP extension 'mysqli' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
mysqli_report(MYSQLI_REPORT_OFF);
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// default values
$config += array(
'charset' => 'utf8',
'timezone' => date('P'),
'username' => ini_get('mysqli.default_user'),
'password' => ini_get('mysqli.default_pw'),
'socket' => ini_get('mysqli.default_socket'),
'port' => NULL,
);
if (!isset($config['host'])) {
$host = ini_get('mysqli.default_host');
if ($host) {
$config['host'] = $host;
$config['port'] = ini_get('mysqli.default_port');
} else {
$config['host'] = NULL;
$config['port'] = NULL;
}
}
$foo = & $config['flags'];
$foo = & $config['database'];
$this->connection = mysqli_init();
if (isset($config['options'])) {
if (is_scalar($config['options'])) {
$config['flags'] = $config['options']; // back compatibility
trigger_error(__CLASS__ . ": configuration item 'options' must be array; for constants MYSQLI_CLIENT_* use 'flags'.", E_USER_NOTICE);
} else {
foreach ((array) $config['options'] as $key => $value) {
mysqli_options($this->connection, $key, $value);
}
}
}
@mysqli_real_connect($this->connection, (empty($config['persistent']) ? '' : 'p:') . $config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $config['socket'], $config['flags']); // intentionally @
if ($errno = mysqli_connect_errno()) {
throw new DibiDriverException(mysqli_connect_error(), $errno);
}
}
if (isset($config['charset'])) {
if (!@mysqli_set_charset($this->connection, $config['charset'])) {
$this->query("SET NAMES '$config[charset]'");
}
}
if (isset($config['sqlmode'])) {
$this->query("SET sql_mode='$config[sqlmode]'");
}
if (isset($config['timezone'])) {
$this->query("SET time_zone='$config[timezone]'");
}
$this->buffered = empty($config['unbuffered']);
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
mysqli_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$res = @mysqli_query($this->connection, $sql, $this->buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); // intentionally @
if (mysqli_errno($this->connection)) {
throw new DibiDriverException(mysqli_error($this->connection), mysqli_errno($this->connection), $sql);
} elseif (is_object($res)) {
return $this->createResultDriver($res);
}
}
/**
* Retrieves information about the most recently executed query.
* @return array
*/
public function getInfo()
{
$res = array();
preg_match_all('#(.+?): +(\d+) *#', mysqli_info($this->connection), $matches, PREG_SET_ORDER);
if (preg_last_error()) {
throw new DibiPcreException;
}
foreach ($matches as $m) {
$res[$m[1]] = (int) $m[2];
}
return $res;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mysqli_affected_rows($this->connection) === -1 ? FALSE : mysqli_affected_rows($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return mysqli_insert_id($this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Returns the connection resource.
* @return mysqli
*/
public function getResource()
{
return @$this->connection->thread_id ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return new DibiMySqlReflector($this);
}
/**
* Result set driver factory.
* @param mysqli_result
* @return IDibiResultDriver
*/
public function createResultDriver(mysqli_result $resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
return "'" . mysqli_real_escape_string($this->connection, $value) . "'";
case dibi::BINARY:
return "_binary'" . mysqli_real_escape_string($this->connection, $value) . "'";
case dibi::IDENTIFIER:
return '`' . str_replace('`', '``', $value) . '`';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 || $offset > 0) {
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && @$this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
if (!$this->buffered) {
throw new DibiNotSupportedException('Row count is not available for unbuffered queries.');
}
return mysqli_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return mysqli_fetch_array($this->resultSet, $assoc ? MYSQLI_ASSOC : MYSQLI_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
if (!$this->buffered) {
throw new DibiNotSupportedException('Cannot seek an unbuffered result set.');
}
return mysqli_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mysqli_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
static $types;
if (empty($types)) {
$consts = get_defined_constants(TRUE);
foreach ($consts['mysqli'] as $key => $value) {
if (strncmp($key, 'MYSQLI_TYPE_', 12) === 0) {
$types[$value] = substr($key, 12);
}
}
$types[MYSQLI_TYPE_TINY] = $types[MYSQLI_TYPE_SHORT] = $types[MYSQLI_TYPE_LONG] = 'INT';
}
$count = mysqli_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) mysqli_fetch_field_direct($this->resultSet, $i);
$columns[] = array(
'name' => $row['name'],
'table' => $row['orgtable'],
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
'nativetype' => $types[$row['type']],
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mysqli_result
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return $this->resultSet === NULL || $this->resultSet->type === NULL ? NULL : $this->resultSet;
}
}

View File

@@ -1,475 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi driver interacting with databases via ODBC connections.
*
* Driver options:
* - dsn => driver specific DSN
* - username (or user)
* - password (or pass)
* - persistent (bool) => try to find a persistent link?
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiOdbcDriver extends DibiObject implements IDibiDriver, IDibiResultDriver, IDibiReflector
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var int|FALSE Affected rows */
private $affectedRows = FALSE;
/** @var int Cursor */
private $row = 0;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('odbc')) {
throw new DibiNotSupportedException("PHP extension 'odbc' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// default values
$config += array(
'username' => ini_get('odbc.default_user'),
'password' => ini_get('odbc.default_pw'),
'dsn' => ini_get('odbc.default_db'),
);
if (empty($config['persistent'])) {
$this->connection = @odbc_connect($config['dsn'], $config['username'], $config['password']); // intentionally @
} else {
$this->connection = @odbc_pconnect($config['dsn'], $config['username'], $config['password']); // intentionally @
}
}
if (!is_resource($this->connection)) {
throw new DibiDriverException(odbc_errormsg() . ' ' . odbc_error());
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
odbc_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->affectedRows = FALSE;
$res = @odbc_exec($this->connection, $sql); // intentionally @
if ($res === FALSE) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection), 0, $sql);
} elseif (is_resource($res)) {
$this->affectedRows = odbc_num_rows($res);
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return $this->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
*/
public function getInsertId($sequence)
{
throw new DibiNotSupportedException('ODBC does not support autoincrementing.');
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
if (!odbc_autocommit($this->connection, FALSE)) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
}
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if (!odbc_commit($this->connection)) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
}
odbc_autocommit($this->connection, TRUE);
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if (!odbc_rollback($this->connection)) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
}
odbc_autocommit($this->connection, TRUE);
}
/**
* Is in transaction?
* @return bool
*/
public function inTransaction()
{
return !odbc_autocommit($this->connection);
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return $this;
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "#m/d/Y H:i:s#" : "#m/d/Y#");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
}
if ($offset) {
throw new DibiNotSupportedException('Offset is not implemented in driver odbc.');
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
// will return -1 with many drivers :-(
return odbc_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
if ($assoc) {
return odbc_fetch_array($this->resultSet, ++$this->row);
} else {
$set = $this->resultSet;
if (!odbc_fetch_row($set, ++$this->row)) {
return FALSE;
}
$count = odbc_num_fields($set);
$cols = array();
for ($i = 1; $i <= $count; $i++) {
$cols[] = odbc_result($set, $i);
}
return $cols;
}
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
$this->row = $row;
return TRUE;
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
odbc_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = odbc_num_fields($this->resultSet);
$columns = array();
for ($i = 1; $i <= $count; $i++) {
$columns[] = array(
'name' => odbc_field_name($this->resultSet, $i),
'table' => NULL,
'fullname' => odbc_field_name($this->resultSet, $i),
'nativetype' => odbc_field_type($this->resultSet, $i),
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
/********************* IDibiReflector ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = odbc_tables($this->connection);
$tables = array();
while ($row = odbc_fetch_array($res)) {
if ($row['TABLE_TYPE'] === 'TABLE' || $row['TABLE_TYPE'] === 'VIEW') {
$tables[] = array(
'name' => $row['TABLE_NAME'],
'view' => $row['TABLE_TYPE'] === 'VIEW',
);
}
}
odbc_free_result($res);
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = odbc_columns($this->connection);
$columns = array();
while ($row = odbc_fetch_array($res)) {
if ($row['TABLE_NAME'] === $table) {
$columns[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => $row['TYPE_NAME'],
'size' => $row['COLUMN_SIZE'],
'nullable' => (bool) $row['NULLABLE'],
'default' => $row['COLUMN_DEF'],
);
}
}
odbc_free_result($res);
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new DibiNotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new DibiNotImplementedException;
}
}

View File

@@ -1,440 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi driver for Oracle database.
*
* Driver options:
* - database => the name of the local Oracle instance or the name of the entry in tnsnames.ora
* - username (or user)
* - password (or pass)
* - charset => character encoding to set
* - formatDate => how to format date in SQL (@see date)
* - formatDateTime => how to format datetime in SQL (@see date)
* - resource (resource) => existing connection resource
* - persistent => Creates persistent connections with oci_pconnect instead of oci_new_connect
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiOracleDriver extends DibiObject implements IDibiDriver, IDibiResultDriver, IDibiReflector
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var bool */
private $autocommit = TRUE;
/** @var string Date and datetime format */
private $fmtDate, $fmtDateTime;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('oci8')) {
throw new DibiNotSupportedException("PHP extension 'oci8' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
$foo = & $config['charset'];
$this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
$this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (empty($config['persistent'])) {
$this->connection = @oci_new_connect($config['username'], $config['password'], $config['database'], $config['charset']); // intentionally @
} else {
$this->connection = @oci_pconnect($config['username'], $config['password'], $config['database'], $config['charset']); // intentionally @
}
if (!$this->connection) {
$err = oci_error();
throw new DibiDriverException($err['message'], $err['code']);
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
oci_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$res = oci_parse($this->connection, $sql);
if ($res) {
oci_execute($res, $this->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
$err = oci_error($res);
if ($err) {
throw new DibiDriverException($err['message'], $err['code'], $sql);
} elseif (is_resource($res)) {
return $this->createResultDriver($res);
}
} else {
$err = oci_error($this->connection);
throw new DibiDriverException($err['message'], $err['code'], $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
*/
public function getAffectedRows()
{
throw new DibiNotImplementedException;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
$row = $this->query("SELECT $sequence.CURRVAL AS ID FROM DUAL")->fetch(TRUE);
return isset($row['ID']) ? (int) $row['ID'] : FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
*/
public function begin($savepoint = NULL)
{
$this->autocommit = FALSE;
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if (!oci_commit($this->connection)) {
$err = oci_error($this->connection);
throw new DibiDriverException($err['message'], $err['code']);
}
$this->autocommit = TRUE;
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if (!oci_rollback($this->connection)) {
$err = oci_error($this->connection);
throw new DibiDriverException($err['message'], $err['code']);
}
$this->autocommit = TRUE;
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return $this;
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'"; // TODO: not tested
case dibi::IDENTIFIER:
// @see http://download.oracle.com/docs/cd/B10500_01/server.920/a96540/sql_elements9a.htm
return '"' . str_replace('"', '""', $value) . '"';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? $this->fmtDateTime : $this->fmtDate);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
$value = str_replace("'", "''", $value);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($offset > 0) {
// see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
. ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
. ') WHERE "__rnum" > '. (int) $offset;
} elseif ($limit >= 0) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
throw new DibiNotSupportedException('Row count is not available for unbuffered queries.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return oci_fetch_array($this->resultSet, ($assoc ? OCI_ASSOC : OCI_NUM) | OCI_RETURN_NULLS);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
throw new DibiNotImplementedException;
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
oci_free_statement($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = oci_num_fields($this->resultSet);
$columns = array();
for ($i = 1; $i <= $count; $i++) {
$columns[] = array(
'name' => oci_field_name($this->resultSet, $i),
'table' => NULL,
'fullname' => oci_field_name($this->resultSet, $i),
'nativetype'=> oci_field_type($this->resultSet, $i),
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
/********************* IDibiReflector ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->query('SELECT * FROM cat');
$tables = array();
while ($row = $res->fetch(FALSE)) {
if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
$tables[] = array(
'name' => $row[0],
'view' => $row[1] === 'VIEW',
);
}
}
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
throw new DibiNotImplementedException;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new DibiNotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new DibiNotImplementedException;
}
}

View File

@@ -1,465 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**
* The dibi driver for PDO.
*
* Driver options:
* - dsn => driver specific DSN
* - username (or user)
* - password (or pass)
* - options (array) => driver specific options {@see PDO::__construct}
* - resource (PDO) => existing connection
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
/** @var PDO Connection resource */
private $connection;
/** @var PDOStatement Resultset resource */
private $resultSet;
/** @var int|FALSE Affected rows */
private $affectedRows = FALSE;
/** @var string */
private $driverName;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('pdo')) {
throw new DibiNotSupportedException("PHP extension 'pdo' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
$foo = & $config['dsn'];
$foo = & $config['options'];
DibiConnection::alias($config, 'resource', 'pdo');
if ($config['resource'] instanceof PDO) {
$this->connection = $config['resource'];
} else {
try {
$this->connection = new PDO($config['dsn'], $config['username'], $config['password'], $config['options']);
} catch (PDOException $e) {
throw new DibiDriverException($e->getMessage(), $e->getCode());
}
}
if (!$this->connection) {
throw new DibiDriverException('Connecting error.');
}
$this->driverName = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
$this->connection = NULL;
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
// must detect if SQL returns result set or num of affected rows
$cmd = strtoupper(substr(ltrim($sql), 0, 6));
static $list = array('UPDATE'=>1, 'DELETE'=>1, 'INSERT'=>1, 'REPLAC'=>1);
$this->affectedRows = FALSE;
if (isset($list[$cmd])) {
$this->affectedRows = $this->connection->exec($sql);
if ($this->affectedRows === FALSE) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1], $sql);
}
} else {
$res = $this->connection->query($sql);
if ($res === FALSE) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1], $sql);
} else {
return $this->createResultDriver($res);
}
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return $this->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
*/
public function getInsertId($sequence)
{
return $this->connection->lastInsertId();
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
if (!$this->connection->beginTransaction()) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
}
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if (!$this->connection->commit()) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
}
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if (!$this->connection->rollBack()) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
}
}
/**
* Returns the connection resource.
* @return PDO
*/
public function getResource()
{
return $this->connection;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
switch ($this->driverName) {
case 'mysql':
return new DibiMySqlReflector($this);
case 'sqlite':
case 'sqlite2':
return new DibiSqliteReflector($this);
default:
throw new DibiNotSupportedException;
}
}
/**
* Result set driver factory.
* @param PDOStatement
* @return IDibiResultDriver
*/
public function createResultDriver(PDOStatement $resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
return $this->connection->quote($value, PDO::PARAM_STR);
case dibi::BINARY:
return $this->connection->quote($value, PDO::PARAM_LOB);
case dibi::IDENTIFIER:
switch ($this->driverName) {
case 'mysql':
return '`' . str_replace('`', '``', $value) . '`';
case 'oci':
case 'pgsql':
return '"' . str_replace('"', '""', $value) . '"';
case 'sqlite':
case 'sqlite2':
return '[' . strtr($value, '[]', ' ') . ']';
case 'odbc':
case 'mssql':
return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
case 'sqlsrv':
return '[' . str_replace(']', ']]', $value) . ']';
default:
return $value;
}
case dibi::BOOL:
return $this->connection->quote($value, PDO::PARAM_BOOL);
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
throw new DibiNotImplementedException;
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit < 0 && $offset < 1) {
return;
}
switch ($this->driverName) {
case 'mysql':
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
break;
case 'pgsql':
if ($limit >= 0) {
$sql .= ' LIMIT ' . (int) $limit;
}
if ($offset > 0) {
$sql .= ' OFFSET ' . (int) $offset;
}
break;
case 'sqlite':
case 'sqlite2':
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
break;
case 'oci':
if ($offset > 0) {
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
. ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
. ') WHERE "__rnum" > '. (int) $offset;
} elseif ($limit >= 0) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
}
break;
case 'odbc':
case 'dblib':
case 'mssql':
case 'sqlsrv':
if ($offset < 1) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t';
break;
}
// intentionally break omitted
default:
throw new DibiNotSupportedException('PDO or driver does not support applying limit or offset.');
}
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return $this->resultSet->rowCount();
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return $this->resultSet->fetch($assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
throw new DibiNotSupportedException('Cannot seek an unbuffered result set.');
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
* @throws DibiException
*/
public function getResultColumns()
{
$count = $this->resultSet->columnCount();
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = @$this->resultSet->getColumnMeta($i); // intentionally @
if ($row === FALSE) {
throw new DibiNotSupportedException('Driver does not support meta data.');
}
// PHP < 5.2.3 compatibility
// @see: http://php.net/manual/en/pdostatement.getcolumnmeta.php#pdostatement.getcolumnmeta.changelog
$row = $row + array(
'table' => NULL,
'native_type' => 'VAR_STRING',
);
$columns[] = array(
'name' => $row['name'],
'table' => $row['table'],
'nativetype' => $row['native_type'],
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return PDOStatement
*/
public function getResultResource()
{
return $this->resultSet;
}
}

View File

@@ -1,663 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi driver for PostgreSQL database.
*
* Driver options:
* - host, hostaddr, port, dbname, user, password, connect_timeout, options, sslmode, service => see PostgreSQL API
* - string => or use connection string
* - schema => the schema search path
* - charset => character encoding to set (default is utf8)
* - persistent (bool) => try to find a persistent link?
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDriver, IDibiReflector
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var int|FALSE Affected rows */
private $affectedRows = FALSE;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('pgsql')) {
throw new DibiNotSupportedException("PHP extension 'pgsql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
$config += array(
'charset' => 'utf8',
);
if (isset($config['string'])) {
$string = $config['string'];
} else {
$string = '';
DibiConnection::alias($config, 'user', 'username');
DibiConnection::alias($config, 'dbname', 'database');
foreach (array('host','hostaddr','port','dbname','user','password','connect_timeout','options','sslmode','service') as $key) {
if (isset($config[$key])) {
$string .= $key . '=' . $config[$key] . ' ';
}
}
}
DibiDriverException::tryError();
if (empty($config['persistent'])) {
$this->connection = pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
} else {
$this->connection = pg_pconnect($string, PGSQL_CONNECT_FORCE_NEW);
}
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, 0);
}
}
if (!is_resource($this->connection)) {
throw new DibiDriverException('Connecting error.');
}
if (isset($config['charset'])) {
DibiDriverException::tryError();
pg_set_client_encoding($this->connection, $config['charset']);
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, 0);
}
}
if (isset($config['schema'])) {
$this->query('SET search_path TO "' . $config['schema'] . '"');
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
pg_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->affectedRows = FALSE;
$res = @pg_query($this->connection, $sql); // intentionally @
if ($res === FALSE) {
throw new DibiDriverException(pg_last_error($this->connection), 0, $sql);
} elseif (is_resource($res)) {
$this->affectedRows = pg_affected_rows($res);
if (pg_num_fields($res)) {
return $this->createResultDriver($res);
}
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return $this->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
*/
public function getInsertId($sequence)
{
if ($sequence === NULL) {
// PostgreSQL 8.1 is needed
$res = $this->query('SELECT LASTVAL()');
} else {
$res = $this->query("SELECT CURRVAL('$sequence')");
}
if (!$res) {
return FALSE;
}
$row = $res->fetch(FALSE);
return is_array($row) ? $row[0] : FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Is in transaction?
* @return bool
*/
public function inTransaction()
{
return !in_array(pg_transaction_status($this->connection), array(PGSQL_TRANSACTION_UNKNOWN, PGSQL_TRANSACTION_IDLE), TRUE);
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return $this;
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
if (!is_resource($this->connection)) {
throw new DibiException('Lost connection to server.');
}
return "'" . pg_escape_string($this->connection, $value) . "'";
case dibi::BINARY:
if (!is_resource($this->connection)) {
throw new DibiException('Lost connection to server.');
}
return "'" . pg_escape_bytea($this->connection, $value) . "'";
case dibi::IDENTIFIER:
// @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
return '"' . str_replace('"', '""', $value) . '"';
case dibi::BOOL:
return $value ? 'TRUE' : 'FALSE';
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? "'Y-m-d H:i:s'" : "'Y-m-d'");
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off
$value = pg_escape_string($this->connection, $value);
$value = strtr($value, array('%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\'));
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return pg_unescape_bytea($value);
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0) {
$sql .= ' LIMIT ' . (int) $limit;
}
if ($offset > 0) {
$sql .= ' OFFSET ' . (int) $offset;
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return pg_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return pg_fetch_array($this->resultSet, NULL, $assoc ? PGSQL_ASSOC : PGSQL_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
return pg_result_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
pg_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = pg_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = array(
'name' => pg_field_name($this->resultSet, $i),
'table' => pg_field_table($this->resultSet, $i),
'nativetype'=> pg_field_type($this->resultSet, $i),
);
$row['fullname'] = $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'];
$columns[] = $row;
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
/********************* IDibiReflector ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$version = pg_parameter_status($this->resource, 'server_version');
if ($version < 7.4) {
throw new DibiDriverException('Reflection requires PostgreSQL 7.4 and newer.');
}
$query = "
SELECT
table_name AS name,
CASE table_type
WHEN 'VIEW' THEN 1
ELSE 0
END AS view
FROM
information_schema.tables
WHERE
table_schema = ANY (current_schemas(false))";
if ($version >= 9.3) {
$query .= '
UNION ALL
SELECT
matviewname, 1
FROM
pg_matviews
WHERE
schemaname = ANY (current_schemas(false))';
}
$res = $this->query($query);
$tables = pg_fetch_all($res->resultSet);
return $tables ? $tables : array();
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$_table = $this->escape($this->escape($table, dibi::IDENTIFIER), dibi::TEXT);
$res = $this->query("
SELECT indkey
FROM pg_class
LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid AND pg_index.indisprimary
WHERE pg_class.oid = $_table::regclass
");
$primary = (int) pg_fetch_object($res->resultSet)->indkey;
$res = $this->query("
SELECT *
FROM information_schema.columns c
JOIN pg_class ON pg_class.relname = c.table_name
JOIN pg_namespace nsp ON nsp.oid = pg_class.relnamespace AND nsp.nspname = c.table_schema
WHERE pg_class.oid = $_table::regclass
ORDER BY c.ordinal_position
");
if (!$res->getRowCount()) {
$res = $this->query("
SELECT
a.attname AS column_name,
pg_type.typname AS udt_name,
a.attlen AS numeric_precision,
a.atttypmod-4 AS character_maximum_length,
NOT a.attnotnull AS is_nullable,
a.attnum AS ordinal_position,
adef.adsrc AS column_default
FROM
pg_attribute a
JOIN pg_type ON a.atttypid = pg_type.oid
JOIN pg_class cls ON a.attrelid = cls.oid
LEFT JOIN pg_attrdef adef ON adef.adnum = a.attnum AND adef.adrelid = a.attrelid
WHERE
cls.relkind IN ('r', 'v', 'mv')
AND a.attrelid = $_table::regclass
AND a.attnum > 0
AND NOT a.attisdropped
ORDER BY ordinal_position
");
}
$columns = array();
while ($row = $res->fetch(TRUE)) {
$size = (int) max($row['character_maximum_length'], $row['numeric_precision']);
$columns[] = array(
'name' => $row['column_name'],
'table' => $table,
'nativetype' => strtoupper($row['udt_name']),
'size' => $size > 0 ? $size : NULL,
'nullable' => $row['is_nullable'] === 'YES' || $row['is_nullable'] === 't',
'default' => $row['column_default'],
'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval',
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$_table = $this->escape($this->escape($table, dibi::IDENTIFIER), dibi::TEXT);
$res = $this->query("
SELECT
a.attnum AS ordinal_position,
a.attname AS column_name
FROM
pg_attribute a
JOIN pg_class cls ON a.attrelid = cls.oid
WHERE
a.attrelid = $_table::regclass
AND a.attnum > 0
AND NOT a.attisdropped
ORDER BY ordinal_position
");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$columns[$row['ordinal_position']] = $row['column_name'];
}
$res = $this->query("
SELECT pg_class2.relname, indisunique, indisprimary, indkey
FROM pg_class
LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid
INNER JOIN pg_class as pg_class2 on pg_class2.oid = pg_index.indexrelid
WHERE pg_class.oid = $_table::regclass
");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['relname']]['name'] = $row['relname'];
$indexes[$row['relname']]['unique'] = $row['indisunique'] === 't';
$indexes[$row['relname']]['primary'] = $row['indisprimary'] === 't';
foreach (explode(' ', $row['indkey']) as $index) {
$indexes[$row['relname']]['columns'][] = $columns[$index];
}
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$_table = $this->escape($this->escape($table, dibi::IDENTIFIER), dibi::TEXT);
$res = $this->query("
SELECT
c.conname AS name,
lt.attname AS local,
c.confrelid::regclass AS table,
ft.attname AS foreign,
CASE c.confupdtype
WHEN 'a' THEN 'NO ACTION'
WHEN 'r' THEN 'RESTRICT'
WHEN 'c' THEN 'CASCADE'
WHEN 'n' THEN 'SET NULL'
WHEN 'd' THEN 'SET DEFAULT'
ELSE 'UNKNOWN'
END AS \"onUpdate\",
CASE c.confdeltype
WHEN 'a' THEN 'NO ACTION'
WHEN 'r' THEN 'RESTRICT'
WHEN 'c' THEN 'CASCADE'
WHEN 'n' THEN 'SET NULL'
WHEN 'd' THEN 'SET DEFAULT'
ELSE 'UNKNOWN'
END AS \"onDelete\",
c.conkey,
lt.attnum AS lnum,
c.confkey,
ft.attnum AS fnum
FROM
pg_constraint c
JOIN pg_attribute lt ON c.conrelid = lt.attrelid AND lt.attnum = ANY (c.conkey)
JOIN pg_attribute ft ON c.confrelid = ft.attrelid AND ft.attnum = ANY (c.confkey)
WHERE
c.contype = 'f'
AND
c.conrelid = $_table::regclass
");
$fKeys = $references = array();
while ($row = $res->fetch(TRUE)) {
if (!isset($fKeys[$row['name']])) {
$fKeys[$row['name']] = array(
'name' => $row['name'],
'table' => $row['table'],
'local' => array(),
'foreign' => array(),
'onUpdate' => $row['onUpdate'],
'onDelete' => $row['onDelete'],
);
$l = explode(',', trim($row['conkey'], '{}'));
$f = explode(',', trim($row['confkey'], '{}'));
$references[$row['name']] = array_combine($l, $f);
}
if (isset($references[$row['name']][$row['lnum']]) && $references[$row['name']][$row['lnum']] === $row['fnum']) {
$fKeys[$row['name']]['local'][] = $row['local'];
$fKeys[$row['name']]['foreign'][] = $row['foreign'];
}
}
return $fKeys;
}
}

View File

@@ -1,422 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**
* The dibi driver for SQLite3 database.
*
* Driver options:
* - database (or file) => the filename of the SQLite3 database
* - formatDate => how to format date in SQL (@see date)
* - formatDateTime => how to format datetime in SQL (@see date)
* - dbcharset => database character encoding (will be converted to 'charset')
* - charset => character encoding to set (default is UTF-8)
* - resource (SQLite3) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiSqlite3Driver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
/** @var SQLite3 Connection resource */
private $connection;
/** @var SQLite3Result Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/** @var string Date and datetime format */
private $fmtDate, $fmtDateTime;
/** @var string character encoding */
private $dbcharset, $charset;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('sqlite3')) {
throw new DibiNotSupportedException("PHP extension 'sqlite3' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
DibiConnection::alias($config, 'database', 'file');
$this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
$this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
if (isset($config['resource']) && $config['resource'] instanceof SQLite3) {
$this->connection = $config['resource'];
} else {
try {
$this->connection = new SQLite3($config['database']);
} catch (Exception $e) {
throw new DibiDriverException($e->getMessage(), $e->getCode());
}
}
$this->dbcharset = empty($config['dbcharset']) ? 'UTF-8' : $config['dbcharset'];
$this->charset = empty($config['charset']) ? 'UTF-8' : $config['charset'];
if (strcasecmp($this->dbcharset, $this->charset) === 0) {
$this->dbcharset = $this->charset = NULL;
}
// enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced)
$version = SQLite3::version();
if ($version['versionNumber'] >= '3006019') {
$this->query('PRAGMA foreign_keys = ON');
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
$this->connection->close();
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
if ($this->dbcharset !== NULL) {
$sql = iconv($this->charset, $this->dbcharset . '//IGNORE', $sql);
}
$res = @$this->connection->query($sql); // intentionally @
if ($this->connection->lastErrorCode()) {
throw new DibiDriverException($this->connection->lastErrorMsg(), $this->connection->lastErrorCode(), $sql);
} elseif ($res instanceof SQLite3Result) {
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return $this->connection->changes();
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return $this->connection->lastInsertRowID();
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'BEGIN');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return new DibiSqliteReflector($this);
}
/**
* Result set driver factory.
* @param SQLite3Result
* @return IDibiResultDriver
*/
public function createResultDriver(SQLite3Result $resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
return "'" . $this->connection->escapeString($value) . "'";
case dibi::BINARY:
return "X'" . bin2hex((string) $value) . "'";
case dibi::IDENTIFIER:
return '[' . strtr($value, '[]', ' ') . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? $this->fmtDateTime : $this->fmtDate);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = addcslashes($this->connection->escapeString($value), '%_\\');
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 || $offset > 0) {
$sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->resultSet && @$this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
* @throws DibiNotSupportedException
*/
public function getRowCount()
{
throw new DibiNotSupportedException('Row count is not available for unbuffered queries.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
$row = $this->resultSet->fetchArray($assoc ? SQLITE3_ASSOC : SQLITE3_NUM);
$charset = $this->charset === NULL ? NULL : $this->charset . '//TRANSLIT';
if ($row && ($assoc || $charset)) {
$tmp = array();
foreach ($row as $k => $v) {
if ($charset !== NULL && is_string($v)) {
$v = iconv($this->dbcharset, $charset, $v);
}
$tmp[str_replace(array('[', ']'), '', $k)] = $v;
}
return $tmp;
}
return $row;
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
* @throws DibiNotSupportedException
*/
public function seek($row)
{
throw new DibiNotSupportedException('Cannot seek an unbuffered result set.');
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
$this->resultSet->finalize();
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = $this->resultSet->numColumns();
$columns = array();
static $types = array(SQLITE3_INTEGER => 'int', SQLITE3_FLOAT => 'float', SQLITE3_TEXT => 'text', SQLITE3_BLOB => 'blob', SQLITE3_NULL => 'null');
for ($i = 0; $i < $count; $i++) {
$columns[] = array(
'name' => $this->resultSet->columnName($i),
'table' => NULL,
'fullname' => $this->resultSet->columnName($i),
'nativetype' => $types[$this->resultSet->columnType($i)],
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return $this->resultSet;
}
/********************* user defined functions ****************d*g**/
/**
* Registers an user defined function for use in SQL statements.
* @param string function name
* @param mixed callback
* @param int num of arguments
* @return void
*/
public function registerFunction($name, $callback, $numArgs = -1)
{
$this->connection->createFunction($name, $callback, $numArgs);
}
/**
* Registers an aggregating user defined function for use in SQL statements.
* @param string function name
* @param mixed callback called for each row of the result set
* @param mixed callback called to aggregate the "stepped" data from each row
* @param int num of arguments
* @return void
*/
public function registerAggregateFunction($name, $rowCallback, $agrCallback, $numArgs = -1)
{
$this->connection->createAggregate($name, $rowCallback, $agrCallback, $numArgs);
}
}

View File

@@ -1,419 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**
* The dibi driver for SQLite database.
*
* Driver options:
* - database (or file) => the filename of the SQLite database
* - persistent (bool) => try to find a persistent link?
* - unbuffered (bool) => sends query without fetching and buffering the result rows automatically?
* - formatDate => how to format date in SQL (@see date)
* - formatDateTime => how to format datetime in SQL (@see date)
* - dbcharset => database character encoding (will be converted to 'charset')
* - charset => character encoding to set (default is UTF-8)
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
* @package dibi\drivers
*/
class DibiSqliteDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool Is buffered (seekable and countable)? */
private $buffered;
/** @var string Date and datetime format */
private $fmtDate, $fmtDateTime;
/** @var string character encoding */
private $dbcharset, $charset;
/**
* @throws DibiNotSupportedException
*/
public function __construct()
{
if (!extension_loaded('sqlite')) {
throw new DibiNotSupportedException("PHP extension 'sqlite' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array & $config)
{
DibiConnection::alias($config, 'database', 'file');
$this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
$this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
$errorMsg = '';
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (empty($config['persistent'])) {
$this->connection = @sqlite_open($config['database'], 0666, $errorMsg); // intentionally @
} else {
$this->connection = @sqlite_popen($config['database'], 0666, $errorMsg); // intentionally @
}
if (!$this->connection) {
throw new DibiDriverException($errorMsg);
}
$this->buffered = empty($config['unbuffered']);
$this->dbcharset = empty($config['dbcharset']) ? 'UTF-8' : $config['dbcharset'];
$this->charset = empty($config['charset']) ? 'UTF-8' : $config['charset'];
if (strcasecmp($this->dbcharset, $this->charset) === 0) {
$this->dbcharset = $this->charset = NULL;
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
sqlite_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
if ($this->dbcharset !== NULL) {
$sql = iconv($this->charset, $this->dbcharset . '//IGNORE', $sql);
}
DibiDriverException::tryError();
if ($this->buffered) {
$res = sqlite_query($this->connection, $sql);
} else {
$res = sqlite_unbuffered_query($this->connection, $sql);
}
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, sqlite_last_error($this->connection), $sql);
} elseif (is_resource($res)) {
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return sqlite_changes($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return sqlite_last_insert_rowid($this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query('BEGIN');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query('COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query('ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
public function getReflector()
{
return new DibiSqliteReflector($this);
}
/**
* Result set driver factory.
* @param resource
* @return IDibiResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . sqlite_escape_string($value) . "'";
case dibi::IDENTIFIER:
return '[' . strtr($value, '[]', ' ') . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
case dibi::DATETIME:
if (!$value instanceof DateTime && !$value instanceof DateTimeInterface) {
$value = new DibiDateTime($value);
}
return $value->format($type === dibi::DATETIME ? $this->fmtDateTime : $this->fmtDate);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
throw new DibiNotSupportedException;
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 || $offset > 0) {
$sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
if (!$this->buffered) {
throw new DibiNotSupportedException('Row count is not available for unbuffered queries.');
}
return sqlite_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
$row = sqlite_fetch_array($this->resultSet, $assoc ? SQLITE_ASSOC : SQLITE_NUM);
$charset = $this->charset === NULL ? NULL : $this->charset . '//TRANSLIT';
if ($row && ($assoc || $charset)) {
$tmp = array();
foreach ($row as $k => $v) {
if ($charset !== NULL && is_string($v)) {
$v = iconv($this->dbcharset, $charset, $v);
}
$tmp[str_replace(array('[', ']'), '', $k)] = $v;
}
return $tmp;
}
return $row;
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
if (!$this->buffered) {
throw new DibiNotSupportedException('Cannot seek an unbuffered result set.');
}
return sqlite_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = sqlite_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$name = str_replace(array('[', ']'), '', sqlite_field_name($this->resultSet, $i));
$pair = explode('.', $name);
$columns[] = array(
'name' => isset($pair[1]) ? $pair[1] : $pair[0],
'table' => isset($pair[1]) ? $pair[0] : NULL,
'fullname' => $name,
'nativetype' => NULL,
);
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
/********************* user defined functions ****************d*g**/
/**
* Registers an user defined function for use in SQL statements.
* @param string function name
* @param mixed callback
* @param int num of arguments
* @return void
*/
public function registerFunction($name, $callback, $numArgs = -1)
{
sqlite_create_function($this->connection, $name, $callback, $numArgs);
}
/**
* Registers an aggregating user defined function for use in SQL statements.
* @param string function name
* @param mixed callback called for each row of the result set
* @param mixed callback called to aggregate the "stepped" data from each row
* @param int num of arguments
* @return void
*/
public function registerAggregateFunction($name, $rowCallback, $agrCallback, $numArgs = -1)
{
sqlite_create_aggregate($this->connection, $name, $rowCallback, $agrCallback, $numArgs);
}
}

View File

@@ -1,161 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* The dibi reflector for SQLite database.
*
* @author David Grudl
* @package dibi\drivers
* @internal
*/
class DibiSqliteReflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query("
SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view')
UNION ALL
SELECT name, type = 'view' as view FROM sqlite_temp_master WHERE type IN ('table', 'view')
ORDER BY name
");
$tables = array();
while ($row = $res->fetch(TRUE)) {
$tables[] = $row;
}
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$meta = $this->driver->query("
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = {$this->driver->escape($table, dibi::TEXT)}
UNION ALL
SELECT sql FROM sqlite_temp_master WHERE type = 'table' AND name = {$this->driver->escape($table, dibi::TEXT)}
")->fetch(TRUE);
$res = $this->driver->query("PRAGMA table_info({$this->driver->escape($table, dibi::IDENTIFIER)})");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$column = $row['name'];
$pattern = "/(\"$column\"|\[$column\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui";
$type = explode('(', $row['type']);
$columns[] = array(
'name' => $column,
'table' => $table,
'fullname' => "$table.$column",
'nativetype' => strtoupper($type[0]),
'size' => isset($type[1]) ? (int) $type[1] : NULL,
'nullable' => $row['notnull'] == '0',
'default' => $row['dflt_value'],
'autoincrement' => (bool) preg_match($pattern, $meta['sql']),
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$res = $this->driver->query("PRAGMA index_list({$this->driver->escape($table, dibi::IDENTIFIER)})");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['name']]['name'] = $row['name'];
$indexes[$row['name']]['unique'] = (bool) $row['unique'];
}
foreach ($indexes as $index => $values) {
$res = $this->driver->query("PRAGMA index_info({$this->driver->escape($index, dibi::IDENTIFIER)})");
while ($row = $res->fetch(TRUE)) {
$indexes[$index]['columns'][$row['seqno']] = $row['name'];
}
}
$columns = $this->getColumns($table);
foreach ($indexes as $index => $values) {
$column = $indexes[$index]['columns'][0];
$primary = FALSE;
foreach ($columns as $info) {
if ($column == $info['name']) {
$primary = $info['vendor']['pk'];
break;
}
}
$indexes[$index]['primary'] = (bool) $primary;
}
if (!$indexes) { // @see http://www.sqlite.org/lang_createtable.html#rowid
foreach ($columns as $column) {
if ($column['vendor']['pk']) {
$indexes[] = array(
'name' => 'ROWID',
'unique' => TRUE,
'primary' => TRUE,
'columns' => array($column['name']),
);
break;
}
}
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
if (!($this->driver instanceof DibiSqlite3Driver)) {
// throw new DibiNotSupportedException; // @see http://www.sqlite.org/foreignkeys.html
}
$res = $this->driver->query("PRAGMA foreign_key_list({$this->driver->escape($table, dibi::IDENTIFIER)})");
$keys = array();
while ($row = $res->fetch(TRUE)) {
$keys[$row['id']]['name'] = $row['id']; // foreign key name
$keys[$row['id']]['local'][$row['seq']] = $row['from']; // local columns
$keys[$row['id']]['table'] = $row['table']; // referenced table
$keys[$row['id']]['foreign'][$row['seq']] = $row['to']; // referenced columns
$keys[$row['id']]['onDelete'] = $row['on_delete'];
$keys[$row['id']]['onUpdate'] = $row['on_update'];
if ($keys[$row['id']]['foreign'][0] == NULL) {
$keys[$row['id']]['foreign'] = NULL;
}
}
return array_values($keys);
}
}

341
dibi/drivers/mysql.php Normal file
View File

@@ -0,0 +1,341 @@
<?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.5b (2006-05-31) 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,
$insertId = FALSE,
$affectedRows = FALSE;
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)
{
$this->insertId = $this->affectedRows = FALSE;
$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,
));
$this->affectedRows = mysql_affected_rows($this->conn);
if ($this->affectedRows < 0) $this->affectedRows = FALSE;
$this->insertId = mysql_insert_id($this->conn);
if ($this->insertId < 1) $this->insertId = FALSE;
return TRUE;
}
public function affectedRows()
{
return $this->affectedRows;
}
public function insertId()
{
return $this->insertId;
}
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
?>

289
dibi/drivers/mysqli.php Normal file
View File

@@ -0,0 +1,289 @@
<?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.5b (2006-05-31) 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,
$insertId = FALSE,
$affectedRows = FALSE;
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)
{
$this->insertId = $this->affectedRows = FALSE;
$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));
$this->affectedRows = mysqli_affected_rows($this->conn);
if ($this->affectedRows < 0) $this->affectedRows = FALSE;
$this->insertId = mysqli_insert_id($this->conn);
if ($this->insertId < 1) $this->insertId = FALSE;
return TRUE;
}
public function affectedRows()
{
return $this->affectedRows;
}
public function insertId()
{
return $this->insertId;
}
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
?>

278
dibi/drivers/odbc.php Normal file
View File

@@ -0,0 +1,278 @@
<?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.5b (2006-05-31) 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,
$affectedRows = FALSE;
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)
{
$this->affectedRows = FALSE;
$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));
$this->affectedRows = odbc_num_rows($this->conn);
if ($this->affectedRows < 0) $this->affectedRows = FALSE;
return TRUE;
}
public function affectedRows()
{
return $this->affectedRows;
}
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
?>

241
dibi/drivers/sqlite.php Normal file
View File

@@ -0,0 +1,241 @@
<?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.5b (2006-05-31) 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,
$insertId = FALSE,
$affectedRows = FALSE;
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)
{
$this->insertId = $this->affectedRows = FALSE;
$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);
$this->affectedRows = sqlite_changes($this->conn);
if ($this->affectedRows < 0) $this->affectedRows = FALSE;
$this->insertId = sqlite_last_insert_rowid($this->conn);
if ($this->insertId < 1) $this->insertId = FALSE;
return TRUE;
}
public function affectedRows()
{
return $this->affectedRows;
}
public function insertId()
{
return $this->insertId;
}
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
?>

View File

@@ -1,543 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* This class is static container class for creating DB objects and
* store connections info.
*
* @author David Grudl
* @package dibi
*/
class dibi
{
/** column type */
const TEXT = 's', // as 'string'
BINARY = 'bin',
BOOL = 'b',
INTEGER = 'i',
FLOAT = 'f',
DATE = 'd',
DATETIME = 't',
TIME = 't';
const IDENTIFIER = 'n',
AFFECTED_ROWS = 'a';
/** @deprecated */
const FIELD_TEXT = self::TEXT,
FIELD_BINARY = self::BINARY,
FIELD_BOOL = self::BOOL,
FIELD_INTEGER = self::INTEGER,
FIELD_FLOAT = self::FLOAT,
FIELD_DATE = self::DATE,
FIELD_DATETIME = self::DATETIME,
FIELD_TIME = self::TIME;
/** version */
const VERSION = '2.2.4',
REVISION = 'released on 2015-10-22';
/** sorting order */
const ASC = 'ASC',
DESC = 'DESC';
/** @var DibiConnection[] Connection registry storage for DibiConnection objects */
private static $registry = array();
/** @var DibiConnection Current connection */
private static $connection;
/** @var array @see addHandler */
private static $handlers = array();
/** @var string Last SQL command @see dibi::query() */
public static $sql;
/** @var int Elapsed time for last query */
public static $elapsedTime;
/** @var int Elapsed time for all queries */
public static $totalTime;
/** @var int Number or queries */
public static $numOfQueries = 0;
/** @var string Default dibi driver */
public static $defaultDriver = 'mysql';
/**
* Static class - cannot be instantiated.
*/
final public function __construct()
{
throw new LogicException('Cannot instantiate static class ' . get_class($this));
}
/********************* connections handling ****************d*g**/
/**
* Creates a new DibiConnection object and connects it to specified database.
* @param mixed connection parameters
* @param string connection name
* @return DibiConnection
* @throws DibiException
*/
public static function connect($config = array(), $name = 0)
{
return self::$connection = self::$registry[$name] = new DibiConnection($config, $name);
}
/**
* Disconnects from database (doesn't destroy DibiConnection object).
* @return void
*/
public static function disconnect()
{
self::getConnection()->disconnect();
}
/**
* Returns TRUE when connection was established.
* @return bool
*/
public static function isConnected()
{
return (self::$connection !== NULL) && self::$connection->isConnected();
}
/**
* Retrieve active connection.
* @param string connection registy name
* @return DibiConnection
* @throws DibiException
*/
public static function getConnection($name = NULL)
{
if ($name === NULL) {
if (self::$connection === NULL) {
throw new DibiException('Dibi is not connected to database.');
}
return self::$connection;
}
if (!isset(self::$registry[$name])) {
throw new DibiException("There is no connection named '$name'.");
}
return self::$registry[$name];
}
/**
* Sets connection.
* @param DibiConnection
* @return DibiConnection
*/
public static function setConnection(DibiConnection $connection)
{
return self::$connection = $connection;
}
/**
* Change active connection.
* @param string connection registy name
* @return void
* @throws DibiException
*/
public static function activate($name)
{
self::$connection = self::getConnection($name);
}
/********************* monostate for active connection ****************d*g**/
/**
* Generates and executes SQL query - Monostate for DibiConnection::query().
* @param array|mixed one or more arguments
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
public static function query($args)
{
$args = func_get_args();
return self::getConnection()->query($args);
}
/**
* Executes the SQL query - Monostate for DibiConnection::nativeQuery().
* @param string SQL statement.
* @return DibiResult|int result set object (if any)
*/
public static function nativeQuery($sql)
{
return self::getConnection()->nativeQuery($sql);
}
/**
* Generates and prints SQL query - Monostate for DibiConnection::test().
* @param array|mixed one or more arguments
* @return bool
*/
public static function test($args)
{
$args = func_get_args();
return self::getConnection()->test($args);
}
/**
* Generates and returns SQL query as DibiDataSource - Monostate for DibiConnection::test().
* @param array|mixed one or more arguments
* @return DibiDataSource
*/
public static function dataSource($args)
{
$args = func_get_args();
return self::getConnection()->dataSource($args);
}
/**
* Executes SQL query and fetch result - Monostate for DibiConnection::query() & fetch().
* @param array|mixed one or more arguments
* @return DibiRow
* @throws DibiException
*/
public static function fetch($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetch();
}
/**
* Executes SQL query and fetch results - Monostate for DibiConnection::query() & fetchAll().
* @param array|mixed one or more arguments
* @return DibiRow[]
* @throws DibiException
*/
public static function fetchAll($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetchAll();
}
/**
* Executes SQL query and fetch first column - Monostate for DibiConnection::query() & fetchSingle().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public static function fetchSingle($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetchSingle();
}
/**
* Executes SQL query and fetch pairs - Monostate for DibiConnection::query() & fetchPairs().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public static function fetchPairs($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetchPairs();
}
/**
* Gets the number of affected rows.
* Monostate for DibiConnection::getAffectedRows()
* @return int number of rows
* @throws DibiException
*/
public static function getAffectedRows()
{
return self::getConnection()->getAffectedRows();
}
/**
* Gets the number of affected rows. Alias for getAffectedRows().
* @return int number of rows
* @throws DibiException
*/
public static function affectedRows()
{
return self::getConnection()->getAffectedRows();
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* Monostate for DibiConnection::getInsertId()
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public static function getInsertId($sequence = NULL)
{
return self::getConnection()->getInsertId($sequence);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column. Alias for getInsertId().
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public static function insertId($sequence = NULL)
{
return self::getConnection()->getInsertId($sequence);
}
/**
* Begins a transaction - Monostate for DibiConnection::begin().
* @param string optional savepoint name
* @return void
* @throws DibiException
*/
public static function begin($savepoint = NULL)
{
self::getConnection()->begin($savepoint);
}
/**
* Commits statements in a transaction - Monostate for DibiConnection::commit($savepoint = NULL).
* @param string optional savepoint name
* @return void
* @throws DibiException
*/
public static function commit($savepoint = NULL)
{
self::getConnection()->commit($savepoint);
}
/**
* Rollback changes in a transaction - Monostate for DibiConnection::rollback().
* @param string optional savepoint name
* @return void
* @throws DibiException
*/
public static function rollback($savepoint = NULL)
{
self::getConnection()->rollback($savepoint);
}
/**
* Gets a information about the current database - Monostate for DibiConnection::getDatabaseInfo().
* @return DibiDatabaseInfo
*/
public static function getDatabaseInfo()
{
return self::getConnection()->getDatabaseInfo();
}
/**
* Import SQL dump from file - extreme fast!
* @param string filename
* @return int count of sql commands
*/
public static function loadFile($file)
{
return self::getConnection()->loadFile($file);
}
/**
* Replacement for majority of dibi::methods() in future.
*/
public static function __callStatic($name, $args)
{
//if ($name = 'select', 'update', ...') {
// return self::command()->$name($args);
//}
return call_user_func_array(array(self::getConnection(), $name), $args);
}
/********************* fluent SQL builders ****************d*g**/
/**
* @return DibiFluent
*/
public static function command()
{
return self::getConnection()->command();
}
/**
* @param string column name
* @return DibiFluent
*/
public static function select($args)
{
$args = func_get_args();
return call_user_func_array(array(self::getConnection(), 'select'), $args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public static function update($table, $args)
{
return self::getConnection()->update($table, $args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public static function insert($table, $args)
{
return self::getConnection()->insert($table, $args);
}
/**
* @param string table
* @return DibiFluent
*/
public static function delete($table)
{
return self::getConnection()->delete($table);
}
/********************* substitutions ****************d*g**/
/**
* Returns substitution hashmap - Monostate for DibiConnection::getSubstitutes().
* @return DibiHashMap
*/
public static function getSubstitutes()
{
return self::getConnection()->getSubstitutes();
}
/********************* misc tools ****************d*g**/
/**
* Prints out a syntax highlighted version of the SQL command or DibiResult.
* @param string|DibiResult
* @param bool return output instead of printing it?
* @return string
*/
public static function dump($sql = NULL, $return = FALSE)
{
ob_start();
if ($sql instanceof DibiResult) {
$sql->dump();
} else {
if ($sql === NULL) {
$sql = self::$sql;
}
static $keywords1 = 'SELECT|(?:ON\s+DUPLICATE\s+KEY)?UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|CALL|UNION|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|LIKE|RLIKE|REGEXP|TRUE|FALSE';
// insert new lines
$sql = " $sql ";
$sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
// reduce spaces
$sql = preg_replace('#[ \t]{2,}#', ' ', $sql);
$sql = wordwrap($sql, 100);
$sql = preg_replace("#([ \t]*\r?\n){2,}#", "\n", $sql);
// syntax highlight
$highlighter = "#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is";
if (PHP_SAPI === 'cli') {
if (substr(getenv('TERM'), 0, 5) === 'xterm') {
$sql = preg_replace_callback($highlighter, array('dibi', 'cliHighlightCallback'), $sql);
}
echo trim($sql) . "\n\n";
} else {
$sql = htmlSpecialChars($sql);
$sql = preg_replace_callback($highlighter, array('dibi', 'highlightCallback'), $sql);
echo '<pre class="dump">', trim($sql), "</pre>\n\n";
}
}
if ($return) {
return ob_get_clean();
} else {
ob_end_flush();
}
}
private static function highlightCallback($matches)
{
if (!empty($matches[1])) { // comment
return '<em style="color:gray">' . $matches[1] . '</em>';
} elseif (!empty($matches[2])) { // error
return '<strong style="color:red">' . $matches[2] . '</strong>';
} elseif (!empty($matches[3])) { // most important keywords
return '<strong style="color:blue">' . $matches[3] . '</strong>';
} elseif (!empty($matches[4])) { // other keywords
return '<strong style="color:green">' . $matches[4] . '</strong>';
}
}
private static function cliHighlightCallback($matches)
{
if (!empty($matches[1])) { // comment
return "\033[1;30m" . $matches[1] . "\033[0m";
} elseif (!empty($matches[2])) { // error
return "\033[1;31m" . $matches[2] . "\033[0m";
} elseif (!empty($matches[3])) { // most important keywords
return "\033[1;34m" . $matches[3] . "\033[0m";
} elseif (!empty($matches[4])) { // other keywords
return "\033[1;32m" . $matches[4] . "\033[0m";
}
}
}

View File

@@ -1,691 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi connection.
*
* @author David Grudl
* @package dibi
*
* @property-read int $affectedRows
* @property-read int $insertId
*/
class DibiConnection extends DibiObject
{
/** @var array of function (DibiEvent $event); Occurs after query is executed */
public $onEvent;
/** @var array Current connection configuration */
private $config;
/** @var IDibiDriver */
private $driver;
/** @var DibiTranslator */
private $translator;
/** @var bool Is connected? */
private $connected = FALSE;
/** @var DibiHashMap Substitutes for identifiers */
private $substitutes;
/**
* Connection options: (see driver-specific options too)
* - lazy (bool) => if TRUE, connection will be established only when required
* - result (array) => result set options
* - formatDateTime => date-time format (if empty, DateTime objects will be returned)
* - profiler (array or bool)
* - run (bool) => enable profiler?
* - file => file to log
* - substitutes (array) => map of driver specific substitutes (under development)
* @param mixed connection parameters
* @param string connection name
* @throws DibiException
*/
public function __construct($config, $name = NULL)
{
if (is_string($config)) {
parse_str($config, $config);
} elseif ($config instanceof Traversable) {
$tmp = array();
foreach ($config as $key => $val) {
$tmp[$key] = $val instanceof Traversable ? iterator_to_array($val) : $val;
}
$config = $tmp;
} elseif (!is_array($config)) {
throw new InvalidArgumentException('Configuration must be array, string or object.');
}
self::alias($config, 'username', 'user');
self::alias($config, 'password', 'pass');
self::alias($config, 'host', 'hostname');
self::alias($config, 'result|formatDate', 'resultDate');
self::alias($config, 'result|formatDateTime', 'resultDateTime');
if (!isset($config['driver'])) {
$config['driver'] = dibi::$defaultDriver;
}
$class = preg_replace(array('#\W#', '#sql#'), array('_', 'Sql'), ucfirst(strtolower($config['driver'])));
$class = "Dibi{$class}Driver";
if (!class_exists($class)) {
include_once dirname(__FILE__) . "/../drivers/$class.php";
if (!class_exists($class, FALSE)) {
throw new DibiException("Unable to create instance of dibi driver '$class'.");
}
}
$config['name'] = $name;
$this->config = $config;
$this->driver = new $class;
$this->translator = new DibiTranslator($this);
// profiler
$profilerCfg = & $config['profiler'];
if (is_scalar($profilerCfg)) {
$profilerCfg = array('run' => (bool) $profilerCfg);
}
if (!empty($profilerCfg['run'])) {
$filter = isset($profilerCfg['filter']) ? $profilerCfg['filter'] : DibiEvent::QUERY;
if (isset($profilerCfg['file'])) {
$this->onEvent[] = array(new DibiFileLogger($profilerCfg['file'], $filter), 'logEvent');
}
if (DibiFirePhpLogger::isAvailable()) {
$this->onEvent[] = array(new DibiFirePhpLogger($filter), 'logEvent');
}
if (!interface_exists('Tracy\IBarPanel') && (interface_exists('Nette\Diagnostics\IBarPanel') || interface_exists('IBarPanel'))) {
$panel = new DibiNettePanel(isset($profilerCfg['explain']) ? $profilerCfg['explain'] : TRUE, $filter);
$panel->register($this);
}
}
$this->substitutes = new DibiHashMap(create_function('$expr', 'return ":$expr:";'));
if (!empty($config['substitutes'])) {
foreach ($config['substitutes'] as $key => $value) {
$this->substitutes->$key = $value;
}
}
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->connected && $this->driver->getResource() && $this->disconnect();
}
/**
* Connects to a database.
* @return void
*/
final public function connect()
{
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::CONNECT) : NULL;
try {
$this->driver->connect($this->config);
$this->connected = TRUE;
$event && $this->onEvent($event->done());
} catch (DibiException $e) {
$event && $this->onEvent($event->done($e));
throw $e;
}
}
/**
* Disconnects from a database.
* @return void
*/
final public function disconnect()
{
$this->driver->disconnect();
$this->connected = FALSE;
}
/**
* 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)
{
$foo = & $config;
foreach (explode('|', $key) as $key) {
$foo = & $foo[$key];
}
if (!isset($foo) && isset($config[$alias])) {
$foo = $config[$alias];
unset($config[$alias]);
}
}
/**
* Returns the driver and connects to a database in lazy mode.
* @return IDibiDriver
*/
final public function getDriver()
{
$this->connected || $this->connect();
return $this->driver;
}
/**
* Generates (translates) and executes SQL query.
* @param array|mixed one or more arguments
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
final public function query($args)
{
$args = func_get_args();
return $this->nativeQuery($this->translateArgs($args));
}
/**
* Generates SQL query.
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
final public function translate($args)
{
$args = func_get_args();
return $this->translateArgs($args);
}
/**
* Generates and prints SQL query.
* @param array|mixed one or more arguments
* @return bool
*/
final public function test($args)
{
$args = func_get_args();
try {
dibi::dump($this->translateArgs($args));
return TRUE;
} catch (DibiException $e) {
if ($e->getSql()) {
dibi::dump($e->getSql());
} else {
echo get_class($e) . ': ' . $e->getMessage() . (PHP_SAPI === 'cli' ? "\n" : '<br>');
}
return FALSE;
}
}
/**
* Generates (translates) and returns SQL query as DibiDataSource.
* @param array|mixed one or more arguments
* @return DibiDataSource
* @throws DibiException
*/
final public function dataSource($args)
{
$args = func_get_args();
return new DibiDataSource($this->translateArgs($args), $this);
}
/**
* Generates SQL query.
* @param array
* @return string
*/
private function translateArgs($args)
{
$this->connected || $this->connect();
return $this->translator->translate($args);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
final public function nativeQuery($sql)
{
$this->connected || $this->connect();
dibi::$sql = $sql;
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::QUERY, $sql) : NULL;
try {
$res = $this->driver->query($sql);
} catch (DibiException $e) {
$event && $this->onEvent($event->done($e));
throw $e;
}
if ($res) {
$res = $this->createResultSet($res);
} else {
$res = $this->driver->getAffectedRows();
}
$event && $this->onEvent($event->done($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 getAffectedRows()
{
$this->connected || $this->connect();
$rows = $this->driver->getAffectedRows();
if (!is_int($rows) || $rows < 0) {
throw new DibiException('Cannot retrieve number of affected rows.');
}
return $rows;
}
/**
* Gets the number of affected rows. Alias for getAffectedRows().
* @return int number of rows
* @throws DibiException
*/
public function affectedRows()
{
return $this->getAffectedRows();
}
/**
* 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 getInsertId($sequence = NULL)
{
$this->connected || $this->connect();
$id = $this->driver->getInsertId($sequence);
if ($id < 1) {
throw new DibiException('Cannot retrieve last generated ID.');
}
return (int) $id;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column. Alias for getInsertId().
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public function insertId($sequence = NULL)
{
return $this->getInsertId($sequence);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
*/
public function begin($savepoint = NULL)
{
$this->connected || $this->connect();
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::BEGIN, $savepoint) : NULL;
try {
$this->driver->begin($savepoint);
$event && $this->onEvent($event->done());
} catch (DibiException $e) {
$event && $this->onEvent($event->done($e));
throw $e;
}
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
*/
public function commit($savepoint = NULL)
{
$this->connected || $this->connect();
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::COMMIT, $savepoint) : NULL;
try {
$this->driver->commit($savepoint);
$event && $this->onEvent($event->done());
} catch (DibiException $e) {
$event && $this->onEvent($event->done($e));
throw $e;
}
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
*/
public function rollback($savepoint = NULL)
{
$this->connected || $this->connect();
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::ROLLBACK, $savepoint) : NULL;
try {
$this->driver->rollback($savepoint);
$event && $this->onEvent($event->done());
} catch (DibiException $e) {
$event && $this->onEvent($event->done($e));
throw $e;
}
}
/**
* Result set factory.
* @param IDibiResultDriver
* @return DibiResult
*/
public function createResultSet(IDibiResultDriver $resultDriver)
{
$res = new DibiResult($resultDriver);
return $res->setFormat(dibi::DATE, $this->config['result']['formatDate'])
->setFormat(dibi::DATETIME, $this->config['result']['formatDateTime']);
}
/********************* fluent SQL builders ****************d*g**/
/**
* @return DibiFluent
*/
public function command()
{
return new DibiFluent($this);
}
/**
* @param string column name
* @return DibiFluent
*/
public function select($args)
{
$args = func_get_args();
return $this->command()->__call('select', $args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public function update($table, $args)
{
if (!(is_array($args) || $args instanceof Traversable)) {
throw new InvalidArgumentException('Arguments must be array or Traversable.');
}
return $this->command()->update('%n', $table)->set($args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public function insert($table, $args)
{
if ($args instanceof Traversable) {
$args = iterator_to_array($args);
} elseif (!is_array($args)) {
throw new InvalidArgumentException('Arguments must be array or Traversable.');
}
return $this->command()->insert()
->into('%n', $table, '(%n)', array_keys($args))->values('%l', $args);
}
/**
* @param string table
* @return DibiFluent
*/
public function delete($table)
{
return $this->command()->delete()->from('%n', $table);
}
/********************* substitutions ****************d*g**/
/**
* Returns substitution hashmap.
* @return DibiHashMap
*/
public function getSubstitutes()
{
return $this->substitutes;
}
/**
* Provides substitution.
* @return string
*/
public function substitute($value)
{
return strpos($value, ':') === FALSE ? $value : preg_replace_callback('#:([^:\s]*):#', array($this, 'subCb'), $value);
}
/**
* Substitution callback.
*/
private function subCb($m)
{
return $this->substitutes->{$m[1]};
}
/********************* shortcuts ****************d*g**/
/**
* Executes SQL query and fetch result - shortcut for query() & fetch().
* @param array|mixed one or more arguments
* @return DibiRow
* @throws DibiException
*/
public function fetch($args)
{
$args = func_get_args();
return $this->query($args)->fetch();
}
/**
* Executes SQL query and fetch results - shortcut for query() & fetchAll().
* @param array|mixed one or more arguments
* @return DibiRow[]
* @throws DibiException
*/
public function fetchAll($args)
{
$args = func_get_args();
return $this->query($args)->fetchAll();
}
/**
* Executes SQL query and fetch first column - shortcut for query() & fetchSingle().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public function fetchSingle($args)
{
$args = func_get_args();
return $this->query($args)->fetchSingle();
}
/**
* Executes SQL query and fetch pairs - shortcut for query() & fetchPairs().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public function fetchPairs($args)
{
$args = func_get_args();
return $this->query($args)->fetchPairs();
}
/********************* misc ****************d*g**/
/**
* Import SQL dump from file - extreme fast!
* @param string filename
* @return int count of sql commands
*/
public function loadFile($file)
{
$this->connected || $this->connect();
@set_time_limit(0); // intentionally @
$handle = @fopen($file, 'r'); // intentionally @
if (!$handle) {
throw new RuntimeException("Cannot open file '$file'.");
}
$count = 0;
$delimiter = ';';
$sql = '';
while (!feof($handle)) {
$s = rtrim(fgets($handle));
if (substr($s, 0, 10) === 'DELIMITER ') {
$delimiter = substr($s, 10);
} elseif (substr($s, -strlen($delimiter)) === $delimiter) {
$sql .= substr($s, 0, -strlen($delimiter));
$this->driver->query($sql);
$sql = '';
$count++;
} else {
$sql .= $s . "\n";
}
}
if (trim($sql) !== '') {
$this->driver->query($sql);
$count++;
}
fclose($handle);
return $count;
}
/**
* Gets a information about the current database.
* @return DibiDatabaseInfo
*/
public function getDatabaseInfo()
{
$this->connected || $this->connect();
return new DibiDatabaseInfo($this->driver->getReflector(), isset($this->config['database']) ? $this->config['database'] : NULL);
}
/**
* Prevents unserialization.
*/
public function __wakeup()
{
throw new DibiNotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
}
/**
* Prevents serialization.
*/
public function __sleep()
{
throw new DibiNotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
}
}

View File

@@ -1,307 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* Default implementation of IDataSource for dibi.
*
* @author David Grudl
* @package dibi
*/
class DibiDataSource extends DibiObject implements IDataSource
{
/** @var DibiConnection */
private $connection;
/** @var string */
private $sql;
/** @var DibiResult */
private $result;
/** @var int */
private $count;
/** @var int */
private $totalCount;
/** @var array */
private $cols = array();
/** @var array */
private $sorting = array();
/** @var array */
private $conds = array();
/** @var int */
private $offset;
/** @var int */
private $limit;
/**
* @param string SQL command or table or view name, as data source
* @param DibiConnection connection
*/
public function __construct($sql, DibiConnection $connection)
{
if (strpbrk($sql, " \t\r\n") === FALSE) {
$this->sql = $connection->getDriver()->escape($sql, dibi::IDENTIFIER); // table name
} else {
$this->sql = '(' . $sql . ') t'; // SQL command
}
$this->connection = $connection;
}
/**
* Selects columns to query.
* @param string|array column name or array of column names
* @param string column alias
* @return self
*/
public function select($col, $as = NULL)
{
if (is_array($col)) {
$this->cols = $col;
} else {
$this->cols[$col] = $as;
}
$this->result = NULL;
return $this;
}
/**
* Adds conditions to query.
* @param mixed conditions
* @return self
*/
public function where($cond)
{
if (is_array($cond)) {
// TODO: not consistent with select and orderBy
$this->conds[] = $cond;
} else {
$this->conds[] = func_get_args();
}
$this->result = $this->count = NULL;
return $this;
}
/**
* Selects columns to order by.
* @param string|array column name or array of column names
* @param string sorting direction
* @return self
*/
public function orderBy($row, $sorting = 'ASC')
{
if (is_array($row)) {
$this->sorting = $row;
} else {
$this->sorting[$row] = $sorting;
}
$this->result = NULL;
return $this;
}
/**
* Limits number of rows.
* @param int limit
* @param int offset
* @return self
*/
public function applyLimit($limit, $offset = NULL)
{
$this->limit = $limit;
$this->offset = $offset;
$this->result = $this->count = NULL;
return $this;
}
/**
* Returns the dibi connection.
* @return DibiConnection
*/
final public function getConnection()
{
return $this->connection;
}
/********************* executing ****************d*g**/
/**
* Returns (and queries) DibiResult.
* @return DibiResult
*/
public function getResult()
{
if ($this->result === NULL) {
$this->result = $this->connection->nativeQuery($this->__toString());
}
return $this->result;
}
/**
* @return DibiResultIterator
*/
public function getIterator()
{
return $this->getResult()->getIterator();
}
/**
* Generates, executes SQL query and fetches the single row.
* @return DibiRow|FALSE array on success, FALSE if no next record
*/
public function fetch()
{
return $this->getResult()->fetch();
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, FALSE if no next record
*/
public function fetchSingle()
{
return $this->getResult()->fetchSingle();
}
/**
* Fetches all records from table.
* @return array
*/
public function fetchAll()
{
return $this->getResult()->fetchAll();
}
/**
* Fetches all records from table and returns associative tree.
* @param string associative descriptor
* @return array
*/
public function fetchAssoc($assoc)
{
return $this->getResult()->fetchAssoc($assoc);
}
/**
* Fetches all records from table like $key => $value pairs.
* @param string associative key
* @param string value
* @return array
*/
public function fetchPairs($key = NULL, $value = NULL)
{
return $this->getResult()->fetchPairs($key, $value);
}
/**
* Discards the internal cache.
* @return void
*/
public function release()
{
$this->result = $this->count = $this->totalCount = NULL;
}
/********************* exporting ****************d*g**/
/**
* Returns this data source wrapped in DibiFluent object.
* @return DibiFluent
*/
public function toFluent()
{
return $this->connection->select('*')->from('(%SQL) t', $this->__toString());
}
/**
* Returns this data source wrapped in DibiDataSource object.
* @return DibiDataSource
*/
public function toDataSource()
{
return new self($this->__toString(), $this->connection);
}
/**
* Returns SQL query.
* @return string
*/
public function __toString()
{
try {
return $this->connection->translate('
SELECT %n', (empty($this->cols) ? '*' : $this->cols), '
FROM %SQL', $this->sql, '
%ex', $this->conds ? array('WHERE %and', $this->conds) : NULL, '
%ex', $this->sorting ? array('ORDER BY %by', $this->sorting) : NULL, '
%ofs %lmt', $this->offset, $this->limit
);
} catch (Exception $e) {
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
/********************* counting ****************d*g**/
/**
* Returns the number of rows in a given data source.
* @return int
*/
public function count()
{
if ($this->count === NULL) {
$this->count = $this->conds || $this->offset || $this->limit
? (int) $this->connection->nativeQuery(
'SELECT COUNT(*) FROM (' . $this->__toString() . ') t'
)->fetchSingle()
: $this->getTotalCount();
}
return $this->count;
}
/**
* Returns the number of rows in a given data source.
* @return int
*/
public function getTotalCount()
{
if ($this->totalCount === NULL) {
$this->totalCount = (int) $this->connection->nativeQuery(
'SELECT COUNT(*) FROM ' . $this->sql
)->fetchSingle();
}
return $this->totalCount;
}
}

View File

@@ -1,708 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* Reflection metadata class for a database.
*
* @author David Grudl
* @package dibi\reflection
*
* @property-read string $name
* @property-read array $tables
* @property-read array $tableNames
*/
class DibiDatabaseInfo extends DibiObject
{
/** @var IDibiReflector */
private $reflector;
/** @var string */
private $name;
/** @var array */
private $tables;
public function __construct(IDibiReflector $reflector, $name)
{
$this->reflector = $reflector;
$this->name = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return DibiTableInfo[]
*/
public function getTables()
{
$this->init();
return array_values($this->tables);
}
/**
* @return string[]
*/
public function getTableNames()
{
$this->init();
$res = array();
foreach ($this->tables as $table) {
$res[] = $table->getName();
}
return $res;
}
/**
* @param string
* @return DibiTableInfo
*/
public function getTable($name)
{
$this->init();
$l = strtolower($name);
if (isset($this->tables[$l])) {
return $this->tables[$l];
} else {
throw new DibiException("Database '$this->name' has no table '$name'.");
}
}
/**
* @param string
* @return bool
*/
public function hasTable($name)
{
$this->init();
return isset($this->tables[strtolower($name)]);
}
/**
* @return void
*/
protected function init()
{
if ($this->tables === NULL) {
$this->tables = array();
foreach ($this->reflector->getTables() as $info) {
$this->tables[strtolower($info['name'])] = new DibiTableInfo($this->reflector, $info);
}
}
}
}
/**
* Reflection metadata class for a database table.
*
* @author David Grudl
* @package dibi\reflection
*
* @property-read string $name
* @property-read bool $view
* @property-read array $columns
* @property-read array $columnNames
* @property-read array $foreignKeys
* @property-read array $indexes
* @property-read DibiIndexInfo $primaryKey
*/
class DibiTableInfo extends DibiObject
{
/** @var IDibiReflector */
private $reflector;
/** @var string */
private $name;
/** @var bool */
private $view;
/** @var array */
private $columns;
/** @var array */
private $foreignKeys;
/** @var array */
private $indexes;
/** @var DibiIndexInfo */
private $primaryKey;
public function __construct(IDibiReflector $reflector, array $info)
{
$this->reflector = $reflector;
$this->name = $info['name'];
$this->view = !empty($info['view']);
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return bool
*/
public function isView()
{
return $this->view;
}
/**
* @return DibiColumnInfo[]
*/
public function getColumns()
{
$this->initColumns();
return array_values($this->columns);
}
/**
* @return string[]
*/
public function getColumnNames()
{
$this->initColumns();
$res = array();
foreach ($this->columns as $column) {
$res[] = $column->getName();
}
return $res;
}
/**
* @param string
* @return DibiColumnInfo
*/
public function getColumn($name)
{
$this->initColumns();
$l = strtolower($name);
if (isset($this->columns[$l])) {
return $this->columns[$l];
} else {
throw new DibiException("Table '$this->name' has no column '$name'.");
}
}
/**
* @param string
* @return bool
*/
public function hasColumn($name)
{
$this->initColumns();
return isset($this->columns[strtolower($name)]);
}
/**
* @return DibiForeignKeyInfo[]
*/
public function getForeignKeys()
{
$this->initForeignKeys();
return $this->foreignKeys;
}
/**
* @return DibiIndexInfo[]
*/
public function getIndexes()
{
$this->initIndexes();
return $this->indexes;
}
/**
* @return DibiIndexInfo
*/
public function getPrimaryKey()
{
$this->initIndexes();
return $this->primaryKey;
}
/**
* @return void
*/
protected function initColumns()
{
if ($this->columns === NULL) {
$this->columns = array();
foreach ($this->reflector->getColumns($this->name) as $info) {
$this->columns[strtolower($info['name'])] = new DibiColumnInfo($this->reflector, $info);
}
}
}
/**
* @return void
*/
protected function initIndexes()
{
if ($this->indexes === NULL) {
$this->initColumns();
$this->indexes = array();
foreach ($this->reflector->getIndexes($this->name) as $info) {
foreach ($info['columns'] as $key => $name) {
$info['columns'][$key] = $this->columns[strtolower($name)];
}
$this->indexes[strtolower($info['name'])] = new DibiIndexInfo($info);
if (!empty($info['primary'])) {
$this->primaryKey = $this->indexes[strtolower($info['name'])];
}
}
}
}
/**
* @return void
*/
protected function initForeignKeys()
{
throw new DibiNotImplementedException;
}
}
/**
* Reflection metadata class for a result set.
*
* @author David Grudl
* @package dibi\reflection
*
* @property-read array $columns
* @property-read array $columnNames
*/
class DibiResultInfo extends DibiObject
{
/** @var IDibiResultDriver */
private $driver;
/** @var array */
private $columns;
/** @var array */
private $names;
public function __construct(IDibiResultDriver $driver)
{
$this->driver = $driver;
}
/**
* @return DibiColumnInfo[]
*/
public function getColumns()
{
$this->initColumns();
return array_values($this->columns);
}
/**
* @param bool
* @return string[]
*/
public function getColumnNames($fullNames = FALSE)
{
$this->initColumns();
$res = array();
foreach ($this->columns as $column) {
$res[] = $fullNames ? $column->getFullName() : $column->getName();
}
return $res;
}
/**
* @param string
* @return DibiColumnInfo
*/
public function getColumn($name)
{
$this->initColumns();
$l = strtolower($name);
if (isset($this->names[$l])) {
return $this->names[$l];
} else {
throw new DibiException("Result set has no column '$name'.");
}
}
/**
* @param string
* @return bool
*/
public function hasColumn($name)
{
$this->initColumns();
return isset($this->names[strtolower($name)]);
}
/**
* @return void
*/
protected function initColumns()
{
if ($this->columns === NULL) {
$this->columns = array();
$reflector = $this->driver instanceof IDibiReflector ? $this->driver : NULL;
foreach ($this->driver->getResultColumns() as $info) {
$this->columns[] = $this->names[$info['name']] = new DibiColumnInfo($reflector, $info);
}
}
}
}
/**
* Reflection metadata class for a table or result set column.
*
* @author David Grudl
* @package dibi\reflection
*
* @property-read string $name
* @property-read string $fullName
* @property-read DibiTableInfo $table
* @property-read string $type
* @property-read mixed $nativeType
* @property-read int $size
* @property-read bool $unsigned
* @property-read bool $nullable
* @property-read bool $autoIncrement
* @property-read mixed $default
*/
class DibiColumnInfo extends DibiObject
{
/** @var array */
private static $types;
/** @var IDibiReflector|NULL when created by DibiResultInfo */
private $reflector;
/** @var array (name, nativetype, [table], [fullname], [size], [nullable], [default], [autoincrement], [vendor]) */
private $info;
public function __construct(IDibiReflector $reflector = NULL, array $info)
{
$this->reflector = $reflector;
$this->info = $info;
}
/**
* @return string
*/
public function getName()
{
return $this->info['name'];
}
/**
* @return string
*/
public function getFullName()
{
return isset($this->info['fullname']) ? $this->info['fullname'] : NULL;
}
/**
* @return bool
*/
public function hasTable()
{
return !empty($this->info['table']);
}
/**
* @return DibiTableInfo
*/
public function getTable()
{
if (empty($this->info['table']) || !$this->reflector) {
throw new DibiException("Table is unknown or not available.");
}
return new DibiTableInfo($this->reflector, array('name' => $this->info['table']));
}
/**
* @return string
*/
public function getTableName()
{
return isset($this->info['table']) ? $this->info['table'] : NULL;
}
/**
* @return string
*/
public function getType()
{
return self::getTypeCache()->{$this->info['nativetype']};
}
/**
* @return mixed
*/
public function getNativeType()
{
return $this->info['nativetype'];
}
/**
* @return int
*/
public function getSize()
{
return isset($this->info['size']) ? (int) $this->info['size'] : NULL;
}
/**
* @return bool
*/
public function isUnsigned()
{
return isset($this->info['unsigned']) ? (bool) $this->info['unsigned'] : NULL;
}
/**
* @return bool
*/
public function isNullable()
{
return isset($this->info['nullable']) ? (bool) $this->info['nullable'] : NULL;
}
/**
* @return bool
*/
public function isAutoIncrement()
{
return isset($this->info['autoincrement']) ? (bool) $this->info['autoincrement'] : NULL;
}
/**
* @return mixed
*/
public function getDefault()
{
return isset($this->info['default']) ? $this->info['default'] : NULL;
}
/**
* @param string
* @return mixed
*/
public function getVendorInfo($key)
{
return isset($this->info['vendor'][$key]) ? $this->info['vendor'][$key] : NULL;
}
/**
* Heuristic type detection.
* @param string
* @return string
* @internal
*/
public static function detectType($type)
{
static $patterns = array(
'^_' => dibi::TEXT, // PostgreSQL arrays
'BYTEA|BLOB|BIN' => dibi::BINARY,
'TEXT|CHAR|POINT|INTERVAL' => dibi::TEXT,
'YEAR|BYTE|COUNTER|SERIAL|INT|LONG|SHORT' => dibi::INTEGER,
'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER' => dibi::FLOAT,
'^TIME$' => dibi::TIME,
'TIME' => dibi::DATETIME, // DATETIME, TIMESTAMP
'DATE' => dibi::DATE,
'BOOL' => dibi::BOOL,
);
foreach ($patterns as $s => $val) {
if (preg_match("#$s#i", $type)) {
return $val;
}
}
return dibi::TEXT;
}
/**
* @internal
*/
public static function getTypeCache()
{
if (self::$types === NULL) {
self::$types = new DibiHashMap(array(__CLASS__, 'detectType'));
}
return self::$types;
}
}
/**
* Reflection metadata class for a foreign key.
*
* @author David Grudl
* @package dibi\reflection
* @todo
*
* @property-read string $name
* @property-read array $references
*/
class DibiForeignKeyInfo extends DibiObject
{
/** @var string */
private $name;
/** @var array of array(local, foreign, onDelete, onUpdate) */
private $references;
public function __construct($name, array $references)
{
$this->name = $name;
$this->references = $references;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return array
*/
public function getReferences()
{
return $this->references;
}
}
/**
* Reflection metadata class for a index or primary key.
*
* @author David Grudl
* @package dibi\reflection
*
* @property-read string $name
* @property-read array $columns
* @property-read bool $unique
* @property-read bool $primary
*/
class DibiIndexInfo extends DibiObject
{
/** @var array (name, columns, [unique], [primary]) */
private $info;
public function __construct(array $info)
{
$this->info = $info;
}
/**
* @return string
*/
public function getName()
{
return $this->info['name'];
}
/**
* @return array
*/
public function getColumns()
{
return $this->info['columns'];
}
/**
* @return bool
*/
public function isUnique()
{
return !empty($this->info['unique']);
}
/**
* @return bool
*/
public function isPrimary()
{
return !empty($this->info['primary']);
}
}

View File

@@ -1,89 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* DateTime with serialization and timestamp support for PHP 5.2.
*
* @author David Grudl
* @package dibi
*/
class DibiDateTime extends DateTime
{
public function __construct($time = 'now', DateTimeZone $timezone = NULL)
{
if (is_numeric($time)) {
parent::__construct('@' . $time);
$this->setTimeZone($timezone ? $timezone : new DateTimeZone(date_default_timezone_get()));
} elseif ($timezone === NULL) {
parent::__construct($time);
} else {
parent::__construct($time, $timezone);
}
}
public function modifyClone($modify = '')
{
$dolly = clone($this);
return $modify ? $dolly->modify($modify) : $dolly;
}
public function modify($modify)
{
parent::modify($modify);
return $this;
}
public function setTimestamp($timestamp)
{
$zone = PHP_VERSION_ID === 50206 ? new DateTimeZone($this->getTimezone()->getName()) : $this->getTimezone();
$this->__construct('@' . $timestamp);
$this->setTimeZone($zone);
return $this;
}
public function getTimestamp()
{
$ts = $this->format('U');
return is_float($tmp = $ts * 1) ? $ts : $tmp;
}
public function __toString()
{
return $this->format('Y-m-d H:i:s');
}
public function __sleep()
{
$zone = $this->getTimezone()->getName();
if ($zone[0] === '+') {
$this->fix = array($this->format('Y-m-d H:i:sP'));
} else {
$this->fix = array($this->format('Y-m-d H:i:s'), $zone);
}
return array('fix');
}
public function __wakeup()
{
if (isset($this->fix[1])) {
$this->__construct($this->fix[0], new DateTimeZone($this->fix[1]));
} else {
$this->__construct($this->fix[0]);
}
unset($this->fix);
}
}

View File

@@ -1,97 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* Profiler & logger event.
*
* @author David Grudl
* @package dibi
*/
class DibiEvent
{
/** event type */
const CONNECT = 1,
SELECT = 4,
INSERT = 8,
DELETE = 16,
UPDATE = 32,
QUERY = 60, // SELECT | INSERT | DELETE | UPDATE
BEGIN = 64,
COMMIT = 128,
ROLLBACK = 256,
TRANSACTION = 448, // BEGIN | COMMIT | ROLLBACK
ALL = 1023;
/** @var DibiConnection */
public $connection;
/** @var int */
public $type;
/** @var string */
public $sql;
/** @var DibiResult|DibiDriverException|NULL */
public $result;
/** @var float */
public $time;
/** @var int */
public $count;
/** @var array */
public $source;
public function __construct(DibiConnection $connection, $type, $sql = NULL)
{
$this->connection = $connection;
$this->type = $type;
$this->sql = trim($sql);
$this->time = -microtime(TRUE);
if ($type === self::QUERY && preg_match('#\(?\s*(SELECT|UPDATE|INSERT|DELETE)#iA', $this->sql, $matches)) {
static $types = array(
'SELECT' => self::SELECT, 'UPDATE' => self::UPDATE,
'INSERT' => self::INSERT, 'DELETE' => self::DELETE,
);
$this->type = $types[strtoupper($matches[1])];
}
$rc = new ReflectionClass('dibi');
$dibiDir = dirname($rc->getFileName()) . DIRECTORY_SEPARATOR;
foreach (debug_backtrace(FALSE) as $row) {
if (isset($row['file']) && is_file($row['file']) && strpos($row['file'], $dibiDir) !== 0) {
$this->source = array($row['file'], (int) $row['line']);
break;
}
}
dibi::$elapsedTime = FALSE;
dibi::$numOfQueries++;
dibi::$sql = $sql;
}
public function done($result = NULL)
{
$this->result = $result;
try {
$this->count = $result instanceof DibiResult ? count($result) : NULL;
} catch (DibiException $e) {
$this->count = NULL;
}
$this->time += microtime(TRUE);
dibi::$elapsedTime = $this->time;
dibi::$totalTime += $this->time;
return $this;
}
}

View File

@@ -1,148 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi common exception.
*
* @author David Grudl
* @package dibi
*/
class DibiException extends Exception
{
/** @var string */
private $sql;
/**
* Construct a dibi 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;
}
/**
* @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 : '');
}
}
/**
* database server exception.
*
* @author David Grudl
* @package dibi
*/
class DibiDriverException extends DibiException
{
/********************* error catching ****************d*g**/
/** @var string */
private static $errorMsg;
/**
* 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.
* @internal
*/
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;
}
}
/**
* PCRE exception.
*
* @author David Grudl
* @package dibi
*/
class DibiPcreException extends Exception
{
public function __construct($message = '%msg.')
{
static $messages = array(
PREG_INTERNAL_ERROR => 'Internal error',
PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted',
PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted',
PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data',
5 => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', // PREG_BAD_UTF8_OFFSET_ERROR
);
$code = preg_last_error();
parent::__construct(str_replace('%msg', isset($messages[$code]) ? $messages[$code] : 'Unknown error', $message), $code);
}
}
/**
* @package dibi
*/
class DibiNotImplementedException extends DibiException
{}
/**
* @package dibi
*/
class DibiNotSupportedException extends DibiException
{}

View File

@@ -1,73 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi file logger.
*
* @author David Grudl
* @package dibi
*/
class DibiFileLogger extends DibiObject
{
/** @var string Name of the file where SQL errors should be logged */
public $file;
/** @var int */
public $filter;
public function __construct($file, $filter = NULL)
{
$this->file = $file;
$this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
}
/**
* After event notification.
* @return void
*/
public function logEvent(DibiEvent $event)
{
if (($event->type & $this->filter) === 0) {
return;
}
$handle = fopen($this->file, 'a');
if (!$handle) {
return; // or throw exception?
}
flock($handle, LOCK_EX);
if ($event->result instanceof Exception) {
$message = $event->result->getMessage();
if ($code = $event->result->getCode()) {
$message = "[$code] $message";
}
fwrite($handle,
"ERROR: $message"
. "\n-- SQL: " . $event->sql
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
. ";\n-- " . date('Y-m-d H:i:s')
. "\n\n"
);
} else {
fwrite($handle,
'OK: ' . $event->sql
. ($event->count ? ";\n-- rows: " . $event->count : '')
. "\n-- takes: " . sprintf('%0.3f ms', $event->time * 1000)
. "\n-- source: " . implode(':', $event->source)
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
. "\n-- " . date('Y-m-d H:i:s')
. "\n\n"
);
}
fclose($handle);
}
}

View File

@@ -1,88 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi FirePHP logger.
*
* @author David Grudl
* @package dibi
*/
class DibiFirePhpLogger extends DibiObject
{
/** maximum number of rows */
static public $maxQueries = 30;
/** maximum SQL length */
static public $maxLength = 1000;
/** @var int */
public $filter;
/** @var int Elapsed time for all queries */
public $totalTime = 0;
/** @var int Number of all queries */
public $numOfQueries = 0;
/** @var array */
private static $fireTable = array(array('Time', 'SQL Statement', 'Rows', 'Connection'));
/**
* @return bool
*/
public static function isAvailable()
{
return isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/');
}
public function __construct($filter = NULL)
{
$this->filter = $filter ? (int) $filter : DibiEvent::QUERY;
}
/**
* After event notification.
* @return void
*/
public function logEvent(DibiEvent $event)
{
if (headers_sent() || ($event->type & $this->filter) === 0 || count(self::$fireTable) > self::$maxQueries) {
return;
}
$this->totalTime += $event->time;
$this->numOfQueries++;
self::$fireTable[] = array(
sprintf('%0.3f', $event->time * 1000),
strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql,
$event->result instanceof Exception ? 'ERROR' : (string) $event->count,
$event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name'),
);
header('X-Wf-Protocol-dibi: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
header('X-Wf-dibi-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');
header('X-Wf-dibi-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
$payload = json_encode(array(
array(
'Type' => 'TABLE',
'Label' => 'dibi profiler (' . $this->numOfQueries . ' SQL queries took ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms)',
),
self::$fireTable,
));
foreach (str_split($payload, 4990) as $num => $s) {
$num++;
header("X-Wf-dibi-1-1-d$num: |$s|\\"); // protocol-, structure-, plugin-, message-index
}
header("X-Wf-dibi-1-1-d$num: |$s|");
}
}

View File

@@ -1,512 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi SQL builder via fluent interfaces. EXPERIMENTAL!
*
* @author David Grudl
* @package dibi
*
* @method DibiFluent select($field)
* @method DibiFluent distinct()
* @method DibiFluent from($table)
* @method DibiFluent where($cond)
* @method DibiFluent groupBy($field)
* @method DibiFluent having($cond)
* @method DibiFluent orderBy($field)
* @method DibiFluent limit(int $limit)
* @method DibiFluent offset(int $offset)
* @method DibiFluent leftJoin($table)
* @method DibiFluent on($cond)
*/
class DibiFluent extends DibiObject implements IDataSource
{
const REMOVE = FALSE;
/** @var array */
public static $masks = array(
'SELECT' => array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'GROUP BY',
'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET'),
'UPDATE' => array('UPDATE', 'SET', 'WHERE', 'ORDER BY', 'LIMIT'),
'INSERT' => array('INSERT', 'INTO', 'VALUES', 'SELECT'),
'DELETE' => array('DELETE', 'FROM', 'USING', 'WHERE', 'ORDER BY', 'LIMIT'),
);
/** @var array default modifiers for arrays */
public static $modifiers = array(
'SELECT' => '%n',
'FROM' => '%n',
'IN' => '%in',
'VALUES' => '%l',
'SET' => '%a',
'WHERE' => '%and',
'HAVING' => '%and',
'ORDER BY' => '%by',
'GROUP BY' => '%by',
);
/** @var array clauses separators */
public static $separators = array(
'SELECT' => ',',
'FROM' => ',',
'WHERE' => 'AND',
'GROUP BY' => ',',
'HAVING' => 'AND',
'ORDER BY' => ',',
'LIMIT' => FALSE,
'OFFSET' => FALSE,
'SET' => ',',
'VALUES' => ',',
'INTO' => FALSE,
);
/** @var array clauses */
public static $clauseSwitches = array(
'JOIN' => 'FROM',
'INNER JOIN' => 'FROM',
'LEFT JOIN' => 'FROM',
'RIGHT JOIN' => 'FROM',
);
/** @var DibiConnection */
private $connection;
/** @var array */
private $setups = array();
/** @var string */
private $command;
/** @var array */
private $clauses = array();
/** @var array */
private $flags = array();
/** @var array */
private $cursor;
/** @var DibiHashMap normalized clauses */
private static $normalizer;
/**
* @param DibiConnection
*/
public function __construct(DibiConnection $connection)
{
$this->connection = $connection;
if (self::$normalizer === NULL) {
self::$normalizer = new DibiHashMap(array(__CLASS__, '_formatClause'));
}
}
/**
* Appends new argument to the clause.
* @param string clause name
* @param array arguments
* @return self
*/
public function __call($clause, $args)
{
$clause = self::$normalizer->$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;
}
// auto-switch to a clause
if (isset(self::$clauseSwitches[$clause])) {
$this->cursor = & $this->clauses[self::$clauseSwitches[$clause]];
}
if (array_key_exists($clause, $this->clauses)) {
// append to clause
$this->cursor = & $this->clauses[$clause];
// TODO: really delete?
if ($args === array(self::REMOVE)) {
$this->cursor = NULL;
return $this;
}
if (isset(self::$separators[$clause])) {
$sep = self::$separators[$clause];
if ($sep === FALSE) { // means: replace
$this->cursor = array();
} elseif (!empty($this->cursor)) {
$this->cursor[] = $sep;
}
}
} else {
// append to currect flow
if ($args === array(self::REMOVE)) {
return $this;
}
$this->cursor[] = $clause;
}
if ($this->cursor === NULL) {
$this->cursor = array();
}
// special types or argument
if (count($args) === 1) {
$arg = $args[0];
// TODO: really ignore TRUE?
if ($arg === TRUE) { // flag
return $this;
} elseif (is_string($arg) && preg_match('#^[a-z:_][a-z0-9_.:]*\z#i', $arg)) { // identifier
$args = array('%n', $arg);
} elseif (is_array($arg) || ($arg instanceof Traversable && !$arg instanceof self)) { // any array
if (isset(self::$modifiers[$clause])) {
$args = array(self::$modifiers[$clause], $arg);
} elseif (is_string(key($arg))) { // associative array
$args = array('%a', $arg);
}
} // case $arg === FALSE is handled above
}
foreach ($args as $arg) {
if ($arg instanceof self) {
$arg = "($arg)";
}
$this->cursor[] = $arg;
}
return $this;
}
/**
* Switch to a clause.
* @param string clause name
* @return self
*/
public function clause($clause)
{
$this->cursor = & $this->clauses[self::$normalizer->$clause];
if ($this->cursor === NULL) {
$this->cursor = array();
}
return $this;
}
/**
* Removes a clause.
* @param string clause name
* @return self
*/
public function removeClause($clause)
{
$this->clauses[self::$normalizer->$clause] = NULL;
return $this;
}
/**
* Change a SQL flag.
* @param string flag name
* @param bool value
* @return self
*/
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)
{
return isset($this->flags[strtoupper($flag)]);
}
/**
* Returns SQL command.
* @return string
*/
final public function getCommand()
{
return $this->command;
}
/**
* Returns the dibi connection.
* @return DibiConnection
*/
final public function getConnection()
{
return $this->connection;
}
/**
* Adds DibiResult setup.
* @param string method
* @param mixed args
* @return self
*/
public function setupResult($method)
{
$this->setups[] = func_get_args();
return $this;
}
/********************* executing ****************d*g**/
/**
* Generates and executes SQL query.
* @param mixed what to return?
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
public function execute($return = NULL)
{
$res = $this->query($this->_export());
switch ($return) {
case dibi::IDENTIFIER:
return $this->connection->getInsertId();
case dibi::AFFECTED_ROWS:
return $this->connection->getAffectedRows();
default:
return $res;
}
}
/**
* Generates, executes SQL query and fetches the single row.
* @return DibiRow|FALSE array on success, FALSE if no next record
*/
public function fetch()
{
if ($this->command === 'SELECT' && !$this->clauses['LIMIT']) {
$result = $this->query($this->limit(1)->_export())->fetch();
$this->removeClause('LIMIT');
return $result;
}
return $this->query($this->_export())->fetch();
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, FALSE if no next record
*/
public function fetchSingle()
{
if ($this->command === 'SELECT' && !$this->clauses['LIMIT']) {
$result = $this->query($this->limit(1)->_export())->fetchSingle();
$this->removeClause('LIMIT');
return $result;
}
return $this->query($this->_export())->fetchSingle();
}
/**
* Fetches all records from table.
* @param int offset
* @param int limit
* @return array
*/
public function fetchAll($offset = NULL, $limit = NULL)
{
return $this->query($this->_export(NULL, array('%ofs %lmt', $offset, $limit)))->fetchAll();
}
/**
* Fetches all records from table and returns associative tree.
* @param string associative descriptor
* @return array
*/
public function fetchAssoc($assoc)
{
return $this->query($this->_export())->fetchAssoc($assoc);
}
/**
* Fetches all records from table like $key => $value pairs.
* @param string associative key
* @param string value
* @return array
*/
public function fetchPairs($key = NULL, $value = NULL)
{
return $this->query($this->_export())->fetchPairs($key, $value);
}
/**
* Required by the IteratorAggregate interface.
* @param int offset
* @param int limit
* @return DibiResultIterator
*/
public function getIterator($offset = NULL, $limit = NULL)
{
return $this->query($this->_export(NULL, array('%ofs %lmt', $offset, $limit)))->getIterator();
}
/**
* 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));
}
/**
* @return int
*/
public function count()
{
return (int) $this->query(array(
'SELECT COUNT(*) FROM (%ex', $this->_export(), ') [data]',
))->fetchSingle();
}
/**
* @return DibiResult
*/
private function query($args)
{
$res = $this->connection->query($args);
foreach ($this->setups as $setup) {
call_user_func_array(array($res, array_shift($setup)), $setup);
}
return $res;
}
/********************* exporting ****************d*g**/
/**
* @return DibiDataSource
*/
public function toDataSource()
{
return new DibiDataSource($this->connection->translate($this->_export()), $this->connection);
}
/**
* Returns SQL query.
* @return string
*/
final public function __toString()
{
try {
return $this->connection->translate($this->_export());
} catch (Exception $e) {
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
/**
* Generates parameters for DibiTranslator.
* @param string clause name
* @return array
*/
protected function _export($clause = NULL, $args = array())
{
if ($clause === NULL) {
$data = $this->clauses;
} else {
$clause = self::$normalizer->$clause;
if (array_key_exists($clause, $this->clauses)) {
$data = array($clause => $this->clauses[$clause]);
} else {
return array();
}
}
foreach ($data as $clause => $statement) {
if ($statement !== NULL) {
$args[] = $clause;
if ($clause === $this->command && $this->flags) {
$args[] = implode(' ', array_keys($this->flags));
}
foreach ($statement as $arg) {
$args[] = $arg;
}
}
}
return $args;
}
/**
* Format camelCase clause name to UPPER CASE.
* @param string
* @return string
* @internal
*/
public static function _formatClause($s)
{
if ($s === 'order' || $s === 'group') {
$s .= 'By';
trigger_error("Did you mean '$s'?", E_USER_NOTICE);
}
return strtoupper(preg_replace('#[a-z](?=[A-Z])#', '$0 ', $s));
}
public function __clone()
{
// remove references
foreach ($this->clauses as $clause => $val) {
$this->clauses[$clause] = & $val;
unset($val);
}
$this->cursor = & $foo;
}
}

View File

@@ -1,73 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* Lazy cached storage.
*
* @author David Grudl
* @package dibi
* @internal
*/
abstract class DibiHashMapBase
{
private $callback;
public function __construct($callback)
{
$this->setCallback($callback);
}
public function setCallback($callback)
{
if (!is_callable($callback)) {
$able = is_callable($callback, TRUE, $textual);
throw new InvalidArgumentException("Handler '$textual' is not " . ($able ? 'callable.' : 'valid PHP callback.'));
}
$this->callback = $callback;
}
public function getCallback()
{
return $this->callback;
}
}
/**
* Lazy cached storage.
*
* @author David Grudl
* @internal
*/
final class DibiHashMap extends DibiHashMapBase
{
public function __set($nm, $val)
{
if ($nm == '') {
$nm = "\xFF";
}
$this->$nm = $val;
}
public function __get($nm)
{
if ($nm == '') {
$nm = "\xFF";
return isset($this->$nm) ? $this->$nm : $this->$nm = call_user_func($this->getCallback(), '');
} else {
return $this->$nm = call_user_func($this->getCallback(), $nm);
}
}
}

View File

@@ -1,35 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* SQL literal value.
*
* @author David Grudl
* @package dibi
*/
class DibiLiteral extends DibiObject
{
/** @var string */
private $value;
public function __construct($value)
{
$this->value = (string) $value;
}
/**
* @return string
*/
public function __toString()
{
return $this->value;
}
}

View File

@@ -1,308 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* DibiObject is the ultimate ancestor of all instantiable classes.
*
* DibiObject is copy of Nette\Object from Nette Framework (https://nette.org).
*
* It defines some handful methods and enhances object core of PHP:
* - access to undeclared members throws exceptions
* - support for conventional properties with getters and setters
* - support for event raising functionality
* - ability to add new methods to class (extension methods)
*
* Properties is a syntactic sugar which allows access public getter and setter
* methods as normal object variables. A property is defined by a getter method
* and optional setter method (no setter method means read-only property).
* <code>
* $val = $obj->label; // equivalent to $val = $obj->getLabel();
* $obj->label = 'Nette'; // equivalent to $obj->setLabel('Nette');
* </code>
* Property names are case-sensitive, and they are written in the camelCaps
* or PascalCaps.
*
* Event functionality is provided by declaration of property named 'on{Something}'
* Multiple handlers are allowed.
* <code>
* public $onClick; // declaration in class
* $this->onClick[] = 'callback'; // attaching event handler
* if (!empty($this->onClick)) ... // are there any handlers?
* $this->onClick($sender, $arg); // raises the event with arguments
* </code>
*
* Adding method to class (i.e. to all instances) works similar to JavaScript
* prototype property. The syntax for adding a new method is:
* <code>
* MyClass::extensionMethod('newMethod', function (MyClass $obj, $arg, ...) { ... });
* $obj = new MyClass;
* $obj->newMethod($x);
* </code>
*
* @author David Grudl
* @package dibi
*/
abstract class DibiObject
{
/** @var array (method => array(type => callback)) */
private static $extMethods;
/**
* Returns the name of the class of this object.
* @return string
*/
final public /*static*/ function getClass()
{
return /*get_called_class()*/ /**/get_class($this)/**/;
}
/**
* Access to reflection.
* @return \ReflectionObject
*/
final public function getReflection()
{
return new ReflectionObject($this);
}
/**
* Call to undefined method.
* @param string method name
* @param array arguments
* @return mixed
* @throws \LogicException
*/
public function __call($name, $args)
{
$class = get_class($this);
if ($name === '') {
throw new LogicException("Call to class '$class' method without name.");
}
// event functionality
if (preg_match('#^on[A-Z]#', $name)) {
$rp = new ReflectionProperty($class, $name);
if ($rp->isPublic() && !$rp->isStatic()) {
$list = $this->$name;
if (is_array($list) || $list instanceof Traversable) {
foreach ($list as $handler) {
/**/if (is_object($handler)) {
call_user_func_array(array($handler, '__invoke'), $args);
} else /**/{
call_user_func_array($handler, $args);
}
}
}
return NULL;
}
}
// extension methods
if ($cb = self::extensionMethod("$class::$name")) {
array_unshift($args, $this);
return call_user_func_array($cb, $args);
}
throw new LogicException("Call to undefined method $class::$name().");
}
/**
* Call to undefined static method.
* @param string method name (in lower case!)
* @param array arguments
* @return mixed
* @throws \LogicException
*/
public static function __callStatic($name, $args)
{
$class = get_called_class();
throw new LogicException("Call to undefined static method $class::$name().");
}
/**
* Adding method to class.
* @param string method name
* @param mixed callback or closure
* @return mixed
*/
public static function extensionMethod($name, $callback = NULL)
{
if (self::$extMethods === NULL || $name === NULL) { // for backwards compatibility
$list = get_defined_functions();
foreach ($list['user'] as $fce) {
$pair = explode('_prototype_', $fce);
if (count($pair) === 2) {
self::$extMethods[$pair[1]][$pair[0]] = $fce;
self::$extMethods[$pair[1]][''] = NULL;
}
}
if ($name === NULL) {
return NULL;
}
}
$name = strtolower($name);
$a = strrpos($name, ':'); // search ::
if ($a === FALSE) {
$class = strtolower(get_called_class());
$l = & self::$extMethods[$name];
} else {
$class = substr($name, 0, $a - 1);
$l = & self::$extMethods[substr($name, $a + 1)];
}
if ($callback !== NULL) { // works as setter
$l[$class] = $callback;
$l[''] = NULL;
return NULL;
}
// works as getter
if (empty($l)) {
return FALSE;
} elseif (isset($l[''][$class])) { // cached value
return $l[''][$class];
}
$cl = $class;
do {
$cl = strtolower($cl);
if (isset($l[$cl])) {
return $l[''][$class] = $l[$cl];
}
} while (($cl = get_parent_class($cl)) !== FALSE);
foreach (class_implements($class) as $cl) {
$cl = strtolower($cl);
if (isset($l[$cl])) {
return $l[''][$class] = $l[$cl];
}
}
return $l[''][$class] = FALSE;
}
/**
* Returns property value. Do not call directly.
* @param string property name
* @return mixed property value
* @throws \LogicException if the property is not defined.
*/
public function & __get($name)
{
$class = get_class($this);
if ($name === '') {
throw new LogicException("Cannot read a class '$class' property without name.");
}
// property getter support
$uname = ucfirst($name);
$m = 'get' . $uname;
if (self::hasAccessor($class, $m)) {
// ampersands:
// - uses & __get() because declaration should be forward compatible (e.g. with Nette\Web\Html)
// - doesn't call & $this->$m because user could bypass property setter by: $x = & $obj->property; $x = 'new value';
$val = $this->$m();
return $val;
}
$m = 'is' . $uname;
if (self::hasAccessor($class, $m)) {
$val = $this->$m();
return $val;
}
throw new LogicException("Cannot read an undeclared property $class::\$$name.");
}
/**
* Sets value of a property. Do not call directly.
* @param string property name
* @param mixed property value
* @return void
* @throws \LogicException if the property is not defined or is read-only
*/
public function __set($name, $value)
{
$class = get_class($this);
if ($name === '') {
throw new LogicException("Cannot assign to a class '$class' property without name.");
}
// property setter support
$uname = ucfirst($name);
if (self::hasAccessor($class, 'get' . $uname) || self::hasAccessor($class, 'is' . $uname)) {
$m = 'set' . $name;
if (self::hasAccessor($class, $m)) {
$this->$m($value);
return;
} else {
throw new LogicException("Cannot assign to a read-only property $class::\$$name.");
}
}
throw new LogicException("Cannot assign to an undeclared property $class::\$$name.");
}
/**
* Is property defined?
* @param string property name
* @return bool
*/
public function __isset($name)
{
return $name !== '' && self::hasAccessor(get_class($this), 'get' . ucfirst($name));
}
/**
* Access to undeclared property.
* @param string property name
* @return void
* @throws \LogicException
*/
public function __unset($name)
{
$class = get_class($this);
throw new LogicException("Cannot unset the property $class::\$$name.");
}
/**
* Has property an accessor?
* @param string class name
* @param string method name
* @return bool
*/
private static function hasAccessor($c, $m)
{
static $cache;
if (!isset($cache[$c])) {
// get_class_methods returns private, protected and public methods of Object (doesn't matter)
// and ONLY PUBLIC methods of descendants (perfect!)
// but returns static methods too (nothing doing...)
// and is much faster than reflection
// (works good since 5.0.4)
$cache[$c] = array_flip(get_class_methods($c));
}
return isset($cache[$c][$m]);
}
}

View File

@@ -1,670 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi result set.
*
* <code>
* $result = dibi::query('SELECT * FROM [table]');
*
* $row = $result->fetch();
* $value = $result->fetchSingle();
* $table = $result->fetchAll();
* $pairs = $result->fetchPairs();
* $assoc = $result->fetchAssoc('id');
* $assoc = $result->fetchAssoc('active,#,id');
*
* unset($result);
* </code>
*
* @author David Grudl
* @package dibi
*
* @property-read int $rowCount
*/
class DibiResult extends DibiObject implements IDataSource
{
/** @var array IDibiResultDriver */
private $driver;
/** @var array Translate table */
private $types = array();
/** @var DibiResultInfo */
private $meta;
/** @var bool Already fetched? Used for allowance for first seek(0) */
private $fetched = FALSE;
/** @var string returned object class */
private $rowClass = 'DibiRow';
/** @var Callback returned object factory*/
private $rowFactory;
/** @var array format */
private $formats = array();
/**
* @param IDibiResultDriver
*/
public function __construct($driver)
{
$this->driver = $driver;
$this->detectTypes();
}
/**
* @deprecated
*/
final public function getResource()
{
return $this->getResultDriver()->getResultResource();
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
final public function free()
{
if ($this->driver !== NULL) {
$this->driver->free();
$this->driver = $this->meta = NULL;
}
}
/**
* Safe access to property $driver.
* @return IDibiResultDriver
* @throws RuntimeException
*/
final public function getResultDriver()
{
if ($this->driver === NULL) {
throw new RuntimeException('Result-set was released from memory.');
}
return $this->driver;
}
/********************* rows ****************d*g**/
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return bool TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
final public function seek($row)
{
return ($row !== 0 || $this->fetched) ? (bool) $this->getResultDriver()->seek($row) : TRUE;
}
/**
* Required by the Countable interface.
* @return int
*/
final public function count()
{
return $this->getResultDriver()->getRowCount();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
final public function getRowCount()
{
return $this->getResultDriver()->getRowCount();
}
/**
* Required by the IteratorAggregate interface.
* @return DibiResultIterator
*/
final public function getIterator()
{
return new DibiResultIterator($this);
}
/********************* fetching rows ****************d*g**/
/**
* Set fetched object class. This class should extend the DibiRow class.
* @param string
* @return self
*/
public function setRowClass($class)
{
$this->rowClass = $class;
return $this;
}
/**
* Returns fetched object class name.
* @return string
*/
public function getRowClass()
{
return $this->rowClass;
}
/**
* Set a factory to create fetched object instances. These should extend the DibiRow class.
* @param callback
* @return self
*/
public function setRowFactory($callback)
{
$this->rowFactory = $callback;
return $this;
}
/**
* Fetches the row at current position, process optional type conversion.
* and moves the internal cursor to the next position
* @return DibiRow|FALSE array on success, FALSE if no next record
*/
final public function fetch()
{
$row = $this->getResultDriver()->fetch(TRUE);
if (!is_array($row)) {
return FALSE;
}
$this->fetched = TRUE;
$this->normalize($row);
if ($this->rowFactory) {
return call_user_func($this->rowFactory, $row);
} elseif ($this->rowClass) {
$row = new $this->rowClass($row);
}
return $row;
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, FALSE if no next record
*/
final public function fetchSingle()
{
$row = $this->getResultDriver()->fetch(TRUE);
if (!is_array($row)) {
return FALSE;
}
$this->fetched = TRUE;
$this->normalize($row);
return reset($row);
}
/**
* Fetches all records from table.
* @param int offset
* @param int limit
* @return DibiRow[]
*/
final public function fetchAll($offset = NULL, $limit = NULL)
{
$limit = $limit === NULL ? -1 : (int) $limit;
$this->seek((int) $offset);
$row = $this->fetch();
if (!$row) {
return array(); // empty result set
}
$data = array();
do {
if ($limit === 0) {
break;
}
$limit--;
$data[] = $row;
} while ($row = $this->fetch());
return $data;
}
/**
* Fetches all records from table and returns associative tree.
* Examples:
* - associative descriptor: col1[]col2->col3
* builds a tree: $tree[$val1][$index][$val2]->col3[$val3] = {record}
* - associative descriptor: col1|col2->col3=col4
* builds a tree: $tree[$val1][$val2]->col3[$val3] = val4
* @param string associative descriptor
* @return DibiRow
* @throws InvalidArgumentException
*/
final public function fetchAssoc($assoc)
{
if (strpos($assoc, ',') !== FALSE) {
return $this->oldFetchAssoc($assoc);
}
$this->seek(0);
$row = $this->fetch();
if (!$row) {
return array(); // empty result set
}
$data = NULL;
$assoc = preg_split('#(\[\]|->|=|\|)#', $assoc, NULL, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
// check columns
foreach ($assoc as $as) {
// offsetExists ignores NULL in PHP 5.2.1, isset() surprisingly NULL accepts
if ($as !== '[]' && $as !== '=' && $as !== '->' && $as !== '|' && !property_exists($row, $as)) {
throw new InvalidArgumentException("Unknown column '$as' in associative descriptor.");
}
}
if ($as === '->') { // must not be last
array_pop($assoc);
}
if (empty($assoc)) {
$assoc[] = '[]';
}
// make associative tree
do {
$x = & $data;
// iterative deepening
foreach ($assoc as $i => $as) {
if ($as === '[]') { // indexed-array node
$x = & $x[];
} elseif ($as === '=') { // "value" node
$x = $row->{$assoc[$i + 1]};
continue 2;
} elseif ($as === '->') { // "object" node
if ($x === NULL) {
$x = clone $row;
$x = & $x->{$assoc[$i + 1]};
$x = NULL; // prepare child node
} else {
$x = & $x->{$assoc[$i + 1]};
}
} elseif ($as !== '|') { // associative-array node
$x = & $x[$row->$as];
}
}
if ($x === NULL) { // build leaf
$x = $row;
}
} while ($row = $this->fetch());
unset($x);
return $data;
}
/**
* @deprecated
*/
private function oldFetchAssoc($assoc)
{
$this->seek(0);
$row = $this->fetch();
if (!$row) {
return array(); // empty result set
}
$data = NULL;
$assoc = explode(',', $assoc);
// strip leading = and @
$leaf = '@'; // gap
$last = count($assoc) - 1;
while ($assoc[$last] === '=' || $assoc[$last] === '@') {
$leaf = $assoc[$last];
unset($assoc[$last]);
$last--;
if ($last < 0) {
$assoc[] = '#';
break;
}
}
do {
$x = & $data;
foreach ($assoc as $i => $as) {
if ($as === '#') { // indexed-array node
$x = & $x[];
} elseif ($as === '=') { // "record" node
if ($x === NULL) {
$x = $row->toArray();
$x = & $x[ $assoc[$i + 1] ];
$x = NULL; // prepare child node
} else {
$x = & $x[ $assoc[$i + 1] ];
}
} elseif ($as === '@') { // "object" node
if ($x === NULL) {
$x = clone $row;
$x = & $x->{$assoc[$i + 1]};
$x = NULL; // prepare child node
} else {
$x = & $x->{$assoc[$i + 1]};
}
} else { // associative-array node
$x = & $x[$row->$as];
}
}
if ($x === NULL) { // build leaf
if ($leaf === '=') {
$x = $row->toArray();
} else {
$x = $row;
}
}
} while ($row = $this->fetch());
unset($x);
return $data;
}
/**
* Fetches all records from table like $key => $value pairs.
* @param string associative key
* @param string value
* @return array
* @throws InvalidArgumentException
*/
final public function fetchPairs($key = NULL, $value = NULL)
{
$this->seek(0);
$row = $this->fetch();
if (!$row) {
return array(); // empty result set
}
$data = array();
if ($value === NULL) {
if ($key !== NULL) {
throw new InvalidArgumentException('Either none or both columns must be specified.');
}
// autodetect
$tmp = array_keys($row->toArray());
$key = $tmp[0];
if (count($row) < 2) { // indexed-array
do {
$data[] = $row[$key];
} while ($row = $this->fetch());
return $data;
}
$value = $tmp[1];
} else {
if (!property_exists($row, $value)) {
throw new InvalidArgumentException("Unknown value column '$value'.");
}
if ($key === NULL) { // indexed-array
do {
$data[] = $row[$value];
} while ($row = $this->fetch());
return $data;
}
if (!property_exists($row, $key)) {
throw new InvalidArgumentException("Unknown key column '$key'.");
}
}
do {
$data[ (string) $row[$key] ] = $row[$value];
} while ($row = $this->fetch());
return $data;
}
/********************* column types ****************d*g**/
/**
* Autodetect column types.
* @return void
*/
private function detectTypes()
{
$cache = DibiColumnInfo::getTypeCache();
try {
foreach ($this->getResultDriver()->getResultColumns() as $col) {
$this->types[$col['name']] = $cache->{$col['nativetype']};
}
} catch (DibiNotSupportedException $e) {
}
}
/**
* Converts values to specified type and format.
* @param array
* @return void
*/
private function normalize(array & $row)
{
foreach ($this->types as $key => $type) {
if (!isset($row[$key])) { // NULL
continue;
}
$value = $row[$key];
if ($value === FALSE || $type === dibi::TEXT) {
} elseif ($type === dibi::INTEGER) {
$row[$key] = is_float($tmp = $value * 1)
? (is_string($value) ? $value : (int) $value)
: $tmp;
} elseif ($type === dibi::FLOAT) {
$value = ltrim($value, '0');
$p = strpos($value, '.');
if ($p !== FALSE) {
$value = rtrim(rtrim($value, '0'), '.');
}
if ($value === '' || $value[0] === '.') {
$value = '0' . $value;
}
$row[$key] = $value === str_replace(',', '.', (string) ($float = (float) $value))
? $float
: $value;
} elseif ($type === dibi::BOOL) {
$row[$key] = ((bool) $value) && $value !== 'f' && $value !== 'F';
} elseif ($type === dibi::DATE || $type === dibi::DATETIME) {
if ((int) $value !== 0 || substr((string) $value, 0, 3) === '00:') { // '', NULL, FALSE, '0000-00-00', ...
$value = new DibiDateTime($value);
$row[$key] = empty($this->formats[$type]) ? $value : $value->format($this->formats[$type]);
}
} elseif ($type === dibi::BINARY) {
$row[$key] = $this->getResultDriver()->unescape($value, $type);
}
}
}
/**
* Define column type.
* @param string column
* @param string type (use constant Dibi::*)
* @return self
*/
final public function setType($col, $type)
{
$this->types[$col] = $type;
return $this;
}
/**
* Returns column type.
* @return string
*/
final public function getType($col)
{
return isset($this->types[$col]) ? $this->types[$col] : NULL;
}
/**
* Sets data format.
* @param string type (use constant Dibi::*)
* @param string format
* @return self
*/
final public function setFormat($type, $format)
{
$this->formats[$type] = $format;
return $this;
}
/**
* Returns data format.
* @return string
*/
final public function getFormat($type)
{
return isset($this->formats[$type]) ? $this->formats[$type] : NULL;
}
/********************* meta info ****************d*g**/
/**
* Returns a meta information about the current result set.
* @return DibiResultInfo
*/
public function getInfo()
{
if ($this->meta === NULL) {
$this->meta = new DibiResultInfo($this->getResultDriver());
}
return $this->meta;
}
/**
* @deprecated
*/
final public function getColumns()
{
return $this->getInfo()->getColumns();
}
/********************* misc tools ****************d*g**/
/**
* Displays complete result set as HTML or text table for debug purposes.
* @return void
*/
final public function dump()
{
$i = 0;
$this->seek(0);
if (PHP_SAPI === 'cli') {
$hasColors = (substr(getenv('TERM'), 0, 5) === 'xterm');
$maxLen = 0;
while ($row = $this->fetch()) {
if ($i === 0) {
foreach ($row as $col => $foo) {
$len = mb_strlen($col);
$maxLen = max($len, $maxLen);
}
}
if ($hasColors) {
echo "\033[1;37m#row: $i\033[0m\n";
} else {
echo "#row: $i\n";
}
foreach ($row as $col => $val) {
$spaces = $maxLen - mb_strlen($col) + 2;
echo "$col" . str_repeat(' ', $spaces) . "$val\n";
}
echo "\n";
$i++;
}
if ($i === 0) {
echo "empty result set\n";
}
echo "\n";
} else {
while ($row = $this->fetch()) {
if ($i === 0) {
echo "\n<table class=\"dump\">\n<thead>\n\t<tr>\n\t\t<th>#row</th>\n";
foreach ($row as $col => $foo) {
echo "\t\t<th>" . htmlSpecialChars($col) . "</th>\n";
}
echo "\t</tr>\n</thead>\n<tbody>\n";
}
echo "\t<tr>\n\t\t<th>", $i, "</th>\n";
foreach ($row as $col) {
//if (is_object($col)) $col = $col->__toString();
echo "\t\t<td>", htmlSpecialChars($col), "</td>\n";
}
echo "\t</tr>\n";
$i++;
}
if ($i === 0) {
echo '<p><em>empty result set</em></p>';
} else {
echo "</tbody>\n</table>\n";
}
}
}
}

View File

@@ -1,107 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* External result set iterator.
*
* This can be returned by DibiResult::getIterator() method or using foreach
* <code>
* $result = dibi::query('SELECT * FROM table');
* foreach ($result as $row) {
* print_r($row);
* }
* unset($result);
* </code>
*
* @author David Grudl
* @package dibi
*/
class DibiResultIterator implements Iterator, Countable
{
/** @var DibiResult */
private $result;
/** @var int */
private $row;
/** @var int */
private $pointer;
/**
* @param DibiResult
*/
public function __construct(DibiResult $result)
{
$this->result = $result;
}
/**
* Rewinds the iterator to the first element.
* @return void
*/
public function rewind()
{
$this->pointer = 0;
$this->result->seek(0);
$this->row = $this->result->fetch();
}
/**
* Returns the key of the current element.
* @return mixed
*/
public function key()
{
return $this->pointer;
}
/**
* Returns the current element.
* @return mixed
*/
public function current()
{
return $this->row;
}
/**
* Moves forward to next element.
* @return void
*/
public function next()
{
$this->row = $this->result->fetch();
$this->pointer++;
}
/**
* Checks if there is a current element after calls to rewind() or next().
* @return bool
*/
public function valid()
{
return !empty($this->row);
}
/**
* Required by the Countable interface.
* @return int
*/
public function count()
{
return $this->result->getRowCount();
}
}

View File

@@ -1,89 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* Result set single row.
*
* @author David Grudl
* @package dibi
*/
class DibiRow implements ArrayAccess, IteratorAggregate, Countable
{
public function __construct($arr)
{
foreach ($arr as $k => $v) {
$this->$k = $v;
}
}
public function toArray()
{
return (array) $this;
}
/**
* Converts value to DateTime object.
* @param string key
* @param string format
* @return DateTime
*/
public function asDateTime($key, $format = NULL)
{
$time = $this[$key];
if (!$time instanceof DibiDateTime) {
if ((int) $time === 0 && substr((string) $time, 0, 3) !== '00:') { // '', NULL, FALSE, '0000-00-00', ...
return NULL;
}
$time = new DibiDateTime($time);
}
return $format === NULL ? $time : $time->format($format);
}
/********************* interfaces ArrayAccess, Countable & IteratorAggregate ****************d*g**/
final public function count()
{
return count((array) $this);
}
final public function getIterator()
{
return new ArrayIterator($this);
}
final public function offsetSet($nm, $val)
{
$this->$nm = $val;
}
final public function offsetGet($nm)
{
return $this->$nm;
}
final public function offsetExists($nm)
{
return isset($this->$nm);
}
final public function offsetUnset($nm)
{
unset($this->$nm);
}
}

View File

@@ -1,613 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* dibi SQL translator.
*
* @author David Grudl
* @package dibi
*/
final class DibiTranslator extends DibiObject
{
/** @var DibiConnection */
private $connection;
/** @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;
/** @var DibiHashMap */
private $identifiers;
public function __construct(DibiConnection $connection)
{
$this->connection = $connection;
$this->identifiers = new DibiHashMap(array($this, 'delimite'));
}
/**
* Generates SQL.
* @param array
* @return string
* @throws DibiException
*/
public function translate(array $args)
{
if (!$this->driver) {
$this->driver = $this->connection->getDriver();
}
$args = array_values($args);
while (count($args) === 1 && is_array($args[0])) { // implicit array expansion
$args = array_values($args[0]);
}
$this->args = $args;
$this->limit = -1;
$this->offset = 0;
$this->hasError = FALSE;
$commandIns = NULL;
$lastArr = NULL;
// shortcuts
$cursor = & $this->cursor;
$cursor = 0;
// conditional sql
$this->ifLevel = $this->ifLevelStart = 0;
$comment = & $this->comment;
$comment = FALSE;
// iterate
$sql = array();
while ($cursor < count($this->args)) {
$arg = $this->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
:(\S*?:)([a-zA-Z0-9._]?)| ## 8,9) :substitution:
%([a-zA-Z~][a-zA-Z0-9~]{0,5})|## 10) modifier
(\?) ## 11) placeholder
)/xs',
*/ // note: this can change $this->args & $this->cursor & ...
. preg_replace_callback('/(?=[`[\'":%?])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?)|%([a-zA-Z~][a-zA-Z0-9~]{0,5})|(\?))/s',
array($this, 'cb'),
substr($arg, $toSkip)
);
if (preg_last_error()) {
throw new DibiPcreException;
}
}
continue;
}
if ($comment) {
$sql[] = '...';
continue;
}
if ($arg instanceof Traversable) {
$arg = iterator_to_array($arg);
}
if (is_array($arg)) {
if (is_string(key($arg))) {
// associative array -> autoselect between SET or VALUES & LIST
if ($commandIns === NULL) {
$commandIns = strtoupper(substr(ltrim($this->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;
}
}
// default processing
$sql[] = $this->formatValue($arg, FALSE);
} // while
if ($comment) {
$sql[] = '*/';
}
$sql = implode(' ', $sql);
if ($this->hasError) {
throw new DibiException('SQL translate error', 0, $sql);
}
// apply limit
if ($this->limit > -1 || $this->offset > 0) {
$this->driver->applyLimit($sql, $this->limit, $this->offset);
}
return $sql;
}
/**
* Apply modifier to single value.
* @param mixed
* @param string
* @return string
*/
public function formatValue($value, $modifier)
{
if ($this->comment) {
return '...';
}
if (!$this->driver) {
$this->driver = $this->connection->getDriver();
}
// array processing (with or without modifier)
if ($value instanceof Traversable) {
$value = iterator_to_array($value);
}
if (is_array($value)) {
$vx = $kx = array();
switch ($modifier) {
case 'and':
case 'or': // key=val AND key IS NULL AND ...
if (empty($value)) {
return '1=1';
}
foreach ($value as $k => $v) {
if (is_string($k)) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$k = $this->identifiers->{$pair[0]} . ' ';
if (!isset($pair[1])) {
$v = $this->formatValue($v, FALSE);
$vx[] = $k . ($v === 'NULL' ? 'IS ' : '= ') . $v;
} elseif ($pair[1] === 'ex') { // TODO: this will be removed
$vx[] = $k . $this->formatValue($v, 'ex');
} else {
$v = $this->formatValue($v, $pair[1]);
if ($pair[1] === 'l' || $pair[1] === 'in') {
$op = 'IN ';
} elseif (strpos($pair[1], 'like') !== FALSE) {
$op = 'LIKE ';
} elseif ($v === 'NULL') {
$op = 'IS ';
} else {
$op = '= ';
}
$vx[] = $k . $op . $v;
}
} else {
$vx[] = $this->formatValue($v, 'ex');
}
}
return '(' . implode(') ' . strtoupper($modifier) . ' (', $vx) . ')';
case 'n': // key, key, ... identifier names
foreach ($value as $k => $v) {
if (is_string($k)) {
$vx[] = $this->identifiers->$k . (empty($v) ? '' : ' AS ' . $this->identifiers->$v);
} else {
$pair = explode('%', $v, 2); // split into identifier & modifier
$vx[] = $this->identifiers->{$pair[0]};
}
}
return implode(', ', $vx);
case 'a': // key=val, key=val, ...
foreach ($value as $k => $v) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$vx[] = $this->identifiers->{$pair[0]} . '='
. $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : FALSE));
}
return implode(', ', $vx);
case 'in':// replaces scalar %in modifier!
case 'l': // (val, val, ...)
foreach ($value as $k => $v) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : FALSE));
}
return '(' . (($vx || $modifier === 'l') ? implode(', ', $vx) : 'NULL') . ')';
case 'v': // (key, key, ...) VALUES (val, val, ...)
foreach ($value as $k => $v) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$kx[] = $this->identifiers->{$pair[0]};
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : FALSE));
}
return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
case 'm': // (key, key, ...) VALUES (val, val, ...), (val, val, ...), ...
foreach ($value as $k => $v) {
if (is_array($v)) {
if (isset($proto)) {
if ($proto !== array_keys($v)) {
$this->hasError = TRUE;
return '**Multi-insert array "' . $k . '" is different.**';
}
} else {
$proto = array_keys($v);
}
} else {
$this->hasError = TRUE;
return '**Unexpected type ' . gettype($v) . '**';
}
$pair = explode('%', $k, 2); // split into identifier & modifier
$kx[] = $this->identifiers->{$pair[0]};
foreach ($v as $k2 => $v2) {
$vx[$k2][] = $this->formatValue($v2, isset($pair[1]) ? $pair[1] : (is_array($v2) ? 'ex' : FALSE));
}
}
foreach ($vx as $k => $v) {
$vx[$k] = '(' . implode(', ', $v) . ')';
}
return '(' . implode(', ', $kx) . ') VALUES ' . implode(', ', $vx);
case 'by': // key ASC, key DESC
foreach ($value as $k => $v) {
if (is_array($v)) {
$vx[] = $this->formatValue($v, 'ex');
} elseif (is_string($k)) {
$v = (is_string($v) && strncasecmp($v, 'd', 1)) || $v > 0 ? 'ASC' : 'DESC';
$vx[] = $this->identifiers->$k . ' ' . $v;
} else {
$vx[] = $this->identifiers->$v;
}
}
return implode(', ', $vx);
case 'ex':
case 'sql':
$translator = new self($this->connection);
return $translator->translate($value);
default: // value, value, value - all with the same modifier
foreach ($value as $v) {
$vx[] = $this->formatValue($v, $modifier);
}
return implode(', ', $vx);
}
}
// with modifier procession
if ($modifier) {
if ($value !== NULL && !is_scalar($value) && !$value instanceof DateTime && !$value instanceof DateTimeInterface) { // array is already processed
$this->hasError = TRUE;
return '**Unexpected type ' . gettype($value) . '**';
}
switch ($modifier) {
case 's': // string
case 'bin':// binary
case 'b': // boolean
return $value === NULL ? 'NULL' : $this->driver->escape($value, $modifier);
case 'sN': // string or NULL
case 'sn':
return $value == '' ? 'NULL' : $this->driver->escape($value, dibi::TEXT); // notice two equal signs
case 'iN': // signed int or NULL
case 'in': // deprecated
if ($value == '') {
$value = NULL;
}
// intentionally break omitted
case 'i': // signed int
case 'u': // unsigned int, ignored
// support for long numbers - keep them unchanged
if (is_string($value) && preg_match('#[+-]?\d++(e\d+)?\z#A', $value)) {
return $value;
} else {
return $value === NULL ? 'NULL' : (string) (int) ($value + 0);
}
case 'f': // float
// support for extreme numbers - keep them unchanged
if (is_string($value) && is_numeric($value) && strpos($value, 'x') === FALSE) {
return $value; // something like -9E-005 is accepted by SQL, HEX values are not
} else {
return $value === NULL ? 'NULL' : rtrim(rtrim(number_format($value + 0, 10, '.', ''), '0'), '.');
}
case 'd': // date
case 't': // datetime
if ($value === NULL) {
return 'NULL';
} else {
if (is_numeric($value)) {
$value = (int) $value; // timestamp
} elseif (is_string($value)) {
$value = new DateTime($value);
}
return $this->driver->escape($value, $modifier);
}
case 'by':
case 'n': // identifier name
return $this->identifiers->$value;
case 'ex':
case 'sql': // preserve as dibi-SQL (TODO: leave only %ex)
$value = (string) $value;
// speed-up - is regexp required?
$toSkip = strcspn($value, '`[\'":');
if (strlen($value) !== $toSkip) {
$value = substr($value, 0, $toSkip)
. preg_replace_callback(
'/(?=[`[\'":])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?))/s',
array($this, 'cb'),
substr($value, $toSkip)
);
if (preg_last_error()) {
throw new DibiPcreException;
}
}
return $value;
case 'SQL': // preserve as real SQL (TODO: rename to %sql)
return (string) $value;
case 'like~': // LIKE string%
return $this->driver->escapeLike($value, 1);
case '~like': // LIKE %string
return $this->driver->escapeLike($value, -1);
case '~like~': // LIKE %string%
return $this->driver->escapeLike($value, 0);
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::TEXT);
} elseif (is_int($value)) {
return (string) $value;
} elseif (is_float($value)) {
return rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
} elseif (is_bool($value)) {
return $this->driver->escape($value, dibi::BOOL);
} elseif ($value === NULL) {
return 'NULL';
} elseif ($value instanceof DateTime || $value instanceof DateTimeInterface) {
return $this->driver->escape($value, dibi::DATETIME);
} elseif ($value instanceof DibiLiteral) {
return (string) $value;
} else {
$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] => substitution
// [9] => substitution flag
// [10] => modifier (when called from self::translate())
// [11] => placeholder (when called from self::translate())
if (!empty($matches[11])) { // placeholder
$cursor = & $this->cursor;
if ($cursor >= count($this->args)) {
$this->hasError = TRUE;
return '**Extra placeholder**';
}
$cursor++;
return $this->formatValue($this->args[$cursor - 1], FALSE);
}
if (!empty($matches[10])) { // modifier
$mod = $matches[10];
$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->identifiers->{$matches[1]};
} elseif ($matches[2]) { // SQL identifiers: [ident]
return $this->identifiers->{$matches[2]};
} elseif ($matches[3]) { // SQL strings: '...'
return $this->driver->escape(str_replace("''", "'", $matches[4]), dibi::TEXT);
} elseif ($matches[5]) { // SQL strings: "..."
return $this->driver->escape(str_replace('""', '"', $matches[6]), dibi::TEXT);
} elseif ($matches[7]) { // string quote
$this->hasError = TRUE;
return '**Alone quote**';
}
if ($matches[8]) { // SQL identifier substitution
$m = substr($matches[8], 0, -1);
$m = $this->connection->getSubstitutes()->$m;
return $matches[9] == '' ? $this->formatValue($m, FALSE) : $m . $matches[9]; // value or identifier
}
die('this should be never executed');
}
/**
* Apply substitutions to indentifier and delimites it.
* @param string indentifier
* @return string
* @internal
*/
public function delimite($value)
{
$value = $this->connection->substitute($value);
$parts = explode('.', $value);
foreach ($parts as & $v) {
if ($v !== '*') {
$v = $this->driver->escape($v, dibi::IDENTIFIER);
}
}
return implode('.', $parts);
}
}

View 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.5b (2006-05-31) 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
View 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.5b (2006-05-31) 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
View 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.5b (2006-05-31) 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);
}
?>

View File

@@ -1,220 +0,0 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
/**
* 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.
* @package dibi
*/
interface IDibiDriver
{
/**
* Connects to a database.
* @param array
* @return void
* @throws DibiException
*/
function connect(array & $config);
/**
* Disconnects from a database.
* @return void
* @throws DibiException
*/
function disconnect();
/**
* Internal: Executes the SQL query.
* @param string SQL statement.
* @return IDibiResultDriver|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 getAffectedRows();
/**
* 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 getInsertId($sequence);
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
function begin($savepoint = NULL);
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
function commit($savepoint = NULL);
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
function rollback($savepoint = NULL);
/**
* Returns the connection resource.
* @return mixed
*/
function getResource();
/**
* Returns the connection reflector.
* @return IDibiReflector
*/
function getReflector();
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
function escape($value, $type);
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
function escapeLike($value, $pos);
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
function applyLimit(& $sql, $limit, $offset);
}
/**
* dibi result set driver interface.
* @package dibi
*/
interface IDibiResultDriver
{
/**
* Returns the number of rows in a result set.
* @return int
*/
function getRowCount();
/**
* 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.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
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 of {name, nativetype [, table, fullname, (int) size, (bool) nullable, (mixed) default, (bool) autoincrement, (array) vendor ]}
*/
function getResultColumns();
/**
* Returns the result set resource.
* @return mixed
*/
function getResultResource();
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
function unescape($value, $type);
}
/**
* dibi driver reflection.
*
* @author David Grudl
* @package dibi
*/
interface IDibiReflector
{
/**
* Returns list of tables.
* @return array of {name [, (bool) view ]}
*/
function getTables();
/**
* Returns metadata for all columns in a table.
* @param string
* @return array of {name, nativetype [, table, fullname, (int) size, (bool) nullable, (mixed) default, (bool) autoincrement, (array) vendor ]}
*/
function getColumns($table);
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array of {name, (array of names) columns [, (bool) unique, (bool) primary ]}
*/
function getIndexes($table);
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
function getForeignKeys($table);
}

295
dibi/libs/parser.php Normal file
View 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.5b (2006-05-31) 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
View 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.5b (2006-05-31) 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 ? 2147483647 /*PHP_INT_MAX till 5.0.5 */ : (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
?>

4
examples/.gitignore vendored
View File

@@ -1,4 +0,0 @@
_test.bat
ref
output
log

40
examples/connect.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
require_once '../dibi/dibi.php';
// use two connections:
// first connection to mysql
$state = dibi::connect(array(
'driver' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
), 1);
if ($state instanceof Exception) {
echo $state;
}
if (!dibi::isConnected()) {
die();
}
// second connection to odbc
dibi::connect(array(
'driver' => 'odbc',
'username' => 'root',
'password' => '***',
'database' => 'Driver={Microsoft Access Driver (*.mdb)};Dbq=C:\\Database.mdb',
), 3);
echo dibi::isConnected();
?>

View File

@@ -1,161 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Connecting to Databases | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
// connects to SQlite using dibi class
echo '<p>Connecting to Sqlite: ';
try {
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to SQlite using DibiConnection object
echo '<p>Connecting to Sqlite: ';
try {
$connection = new DibiConnection(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MySQL using DSN
echo '<p>Connecting to MySQL: ';
try {
dibi::connect('driver=mysql&host=localhost&username=root&password=xxx&database=test&charset=cp1250');
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MySQLi using array
echo '<p>Connecting to MySQLi: ';
try {
dibi::connect(array(
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => 'xxx',
'database' => 'dibi',
'options' => array(
MYSQLI_OPT_CONNECT_TIMEOUT => 30,
),
'flags' => MYSQLI_CLIENT_COMPRESS,
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to ODBC
echo '<p>Connecting to ODBC: ';
try {
dibi::connect(array(
'driver' => 'odbc',
'username' => 'root',
'password' => '***',
'dsn' => 'Driver={Microsoft Access Driver (*.mdb)};Dbq='.__DIR__.'/data/sample.mdb',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to PostgreSql
echo '<p>Connecting to PostgreSql: ';
try {
dibi::connect(array(
'driver' => 'postgre',
'string' => 'host=localhost port=5432 dbname=mary',
'persistent' => TRUE,
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to PDO
echo '<p>Connecting to Sqlite via PDO: ';
try {
dibi::connect(array(
'driver' => 'pdo',
'dsn' => 'sqlite2::memory:',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MS SQL
echo '<p>Connecting to MS SQL: ';
try {
dibi::connect(array(
'driver' => 'mssql',
'host' => 'localhost',
'username' => 'root',
'password' => 'xxx',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MS SQL 2005
echo '<p>Connecting to MS SQL 2005: ';
try {
dibi::connect(array(
'driver' => 'mssql2005',
'host' => '(local)',
'username' => 'Administrator',
'password' => 'xxx',
'database' => 'main',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to Oracle
echo '<p>Connecting to Oracle: ';
try {
dibi::connect(array(
'driver' => 'oracle',
'username' => 'root',
'password' => 'xxx',
'database' => 'db',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,64 +0,0 @@
body {
font: 15px/1.5 Tahoma, Verdana, Myriad Web, Syntax, sans-serif;
color: #333;
background: #fff url('dibi-powered.gif') no-repeat 99% 1em;
margin: 1.6em;
padding: 0;
}
h1, h2 {
font-size: 210%;
font-weight: normal;
color: #036;
}
h2 {
font-size: 150%;
}
a {
color: #000080;
}
table.dump {
padding: 0;
margin: 0;
border-collapse:collapse;
}
table.dump td, table.dump th {
color: #505767;
background: #fff;
border: 1px solid #d1cdab;
padding: 6px 6px 6px 12px;
text-align: left;
}
table.dump th {
font-size: 80%;
color: #525b37;
background: #e3e9ba;
}
/* dump() */
pre.tracy-dump, pre.dump {
color: #444; background: white;
border: 1px solid silver;
padding: 1em;
margin: 1em 0;
}
pre.tracy-dump .php-array, pre.tracy-dump .php-object {
color: #C22;
}
pre.tracy-dump .php-string {
color: #080;
}
pre.tracy-dump .php-int, pre.tracy-dump .php-float {
color: #37D;
}
pre.tracy-dump .php-null, pre.tracy-dump .php-bool {
color: black;
}
pre.tracy-dump .php-visibility {
font-size: 85%; color: #999;
}

View File

@@ -1,49 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Database Reflection | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// retrieve database reflection
$database = dibi::getDatabaseInfo();
echo "<h2>Database '{$database->name}'</h2>\n";
echo "<ul>\n";
foreach ($database->getTables() as $table) {
echo '<li>', ($table->view ? 'view' : 'table') . " $table->name</li>\n";
}
echo "</ul>\n";
// table reflection
$table = $database->getTable('products');
echo "<h2>Table '{$table->name}'</h2>\n";
echo "Columns\n";
echo "<ul>\n";
foreach ($table->getColumns() as $column) {
echo "<li>{$column->name} <i>{$column->nativeType}</i> <code>{$column->default}</code></li>\n";
}
echo "</ul>\n";
echo 'Indexes';
echo "<ul>\n";
foreach ($table->getIndexes() as $index) {
echo "<li>{$index->name} " . ($index->primary ? 'primary ' : '') . ($index->unique ? 'unique' : '') . ' (';
foreach ($index->getColumns() as $column) {
echo "$column->name, ";
}
echo ")</li>\n";
}
echo "</ul>\n";

View File

@@ -1,32 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Dumping SQL and Result Set | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
$res = dibi::query('
SELECT * FROM products
INNER JOIN orders USING (product_id)
INNER JOIN customers USING (customer_id)
');
echo '<h2>dibi::dump()</h2>';
// dump last query (dibi::$sql)
dibi::dump();
// dump result table
echo '<h2>DibiResult::dump()</h2>';
$res->dump();

52
examples/fetch.php Normal file
View File

@@ -0,0 +1,52 @@
<pre>
<?php
require_once '../dibi/dibi.php';
dibi::$debug = true;
// mysql
dibi::connect(array(
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
));
if (!dibi::isConnected())
die('Not connected');
$res = dibi::query('SELECT * FROM table');
// fetch a single value
$value = $res->fetchSingle();
// fetch complete result set
$all = $res->fetchAll();
// fetch complete result set like association array
$assoc = $res->fetchAll('id');
$assoc = $res->fetchAll('id', 'id2');
// fetch complete result set like pairs key => value
$pairs = $res->fetchPairs('id', 'name');
// fetch row by row
foreach ($res as $row => $fields) {
print_r($fields);
}
// fetch row by row with defined offset and limit
foreach ($res->getIterator(2, 3) as $row => $fields) {
print_r($fields);
}
?>

View File

@@ -1,92 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Fetching Examples | dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
Tracy\Debugger::enable();
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
/*
TABLE products
product_id | title
-----------+----------
1 | Chair
2 | Table
3 | Computer
*/
// fetch a single row
echo "<h2>fetch()</h2>\n";
$row = dibi::fetch('SELECT title FROM products');
Tracy\Dumper::dump($row); // Chair
// fetch a single value
echo "<h2>fetchSingle()</h2>\n";
$value = dibi::fetchSingle('SELECT title FROM products');
Tracy\Dumper::dump($value); // Chair
// fetch complete result set
echo "<h2>fetchAll()</h2>\n";
$all = dibi::fetchAll('SELECT * FROM products');
Tracy\Dumper::dump($all);
// fetch complete result set like association array
echo "<h2>fetchAssoc('title')</h2>\n";
$res = dibi::query('SELECT * FROM products');
$assoc = $res->fetchAssoc('title'); // key
Tracy\Dumper::dump($assoc);
// fetch complete result set like pairs key => value
echo "<h2>fetchPairs('product_id', 'title')</h2>\n";
$res = dibi::query('SELECT * FROM products');
$pairs = $res->fetchPairs('product_id', 'title');
Tracy\Dumper::dump($pairs);
// fetch row by row
echo "<h2>using foreach</h2>\n";
$res = dibi::query('SELECT * FROM products');
foreach ($res as $n => $row) {
Tracy\Dumper::dump($row);
}
// more complex association array
$res = dibi::query('
SELECT *
FROM products
INNER JOIN orders USING (product_id)
INNER JOIN customers USING (customer_id)
');
echo "<h2>fetchAssoc('name|title')</h2>\n";
$assoc = $res->fetchAssoc('name|title'); // key
Tracy\Dumper::dump($assoc);
echo "<h2>fetchAssoc('name[]title')</h2>\n";
$res = dibi::query('SELECT * FROM products INNER JOIN orders USING (product_id) INNER JOIN customers USING (customer_id)');
$assoc = $res->fetchAssoc('name[]title'); // key
Tracy\Dumper::dump($assoc);
echo "<h2>fetchAssoc('name->title')</h2>\n";
$res = dibi::query('SELECT * FROM products INNER JOIN orders USING (product_id) INNER JOIN customers USING (customer_id)');
$assoc = $res->fetchAssoc('name->title'); // key
Tracy\Dumper::dump($assoc);

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Importing SQL Dump from File | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
$count = dibi::loadFile('compress.zlib://data/sample.dump.sql.gz');
echo 'Number of SQL commands:', $count;

14
examples/log.sql Normal file
View File

@@ -0,0 +1,14 @@
Successfully connected to DB 'mysql'
SELECT * FROM `nucleus_item` WHERE `inumber` = 38;
-- Result: object(DibiMySqlResult) rows: 1
-- Takes: 4.994 ms
SELECT * FROM `nucleus_item` WHERE `inumber` < 38;
-- Result: object(DibiMySqlResult) rows: 29
-- Takes: 135.842 ms
SELECT * FROM `*nucleus_item` WHERE `inumber` < 38;
-- Result: Query error: Can't find file: '.\dgx\*nucleus_item.frm' (errno: 22)
-- Takes: 121.454 ms

31
examples/logging.php Normal file
View File

@@ -0,0 +1,31 @@
<pre>
<?php
require_once '../dibi/dibi.php';
dibi::$logfile = 'log.sql';
// mysql
dibi::connect(array(
'driver' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
));
$res = dibi::query('SELECT * FROM [nucleus_item] WHERE [inumber] = %i', 38);
$res = dibi::query('SELECT * FROM [nucleus_item] WHERE [inumber] < %i', 38);
$res = dibi::query('SELECT * FROM [*nucleus_item] WHERE [inumber] < %i', 38);
?>

34
examples/metatypes.php Normal file
View File

@@ -0,0 +1,34 @@
<pre>
<?php
require_once '../dibi/dibi.php';
// mysql
dibi::connect(array(
'driver' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
));
$res = dibi::query('SELECT * FROM [nucleus_item] WHERE [inumber] <> %i', 38);
$res = dibi::query('SELECT * FROM [nucleus_item] WHERE [inumber] <> %i', 38);
// auto-convert this field to integer
$res->setType('inumber', DibiResult::FIELD_INTEGER);
$record = $res->fetch();
var_dump($record);
// auto-detect all types
$res->setType(TRUE);
$record = $res->fetch();
var_dump($record);
?>

View File

@@ -1,61 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Query Language & Conditions | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// some variables
$cond1 = TRUE;
$cond2 = FALSE;
$foo = -1;
$bar = 2;
// conditional variable
$name = $cond1 ? 'K%' : NULL;
// if & end
dibi::test('
SELECT *
FROM customers
%if', isset($name), 'WHERE name LIKE ?', $name, '%end'
);
// -> SELECT * FROM customers WHERE name LIKE 'K%'
// if & else & (optional) end
dibi::test('
SELECT *
FROM people
WHERE id > 0
%if', ($foo > 0), 'AND foo=?', $foo, '
%else %if', ($bar > 0), 'AND bar=?', $bar, '
');
// -> SELECT * FROM people WHERE id > 0 AND bar=2
// nested condition
dibi::test('
SELECT *
FROM customers
WHERE
%if', isset($name), 'name LIKE ?', $name, '
%if', $cond2, 'AND admin=1 %end
%else 1 LIMIT 10 %end'
);
// -> SELECT * FROM customers WHERE LIMIT 10
// IF()
dibi::test('UPDATE products SET', array(
'price' => array('IF(price_fixed, price, ?)', 123),
));
// -> SELECT * FROM customers WHERE LIMIT 10

View File

@@ -1,87 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Query Language Basic Examples | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// SELECT
$ipMask = '192.168.%';
$timestamp = mktime(0, 0, 0, 10, 13, 1997);
dibi::test('
SELECT COUNT(*) as [count]
FROM [comments]
WHERE [ip] LIKE ?', $ipMask, '
AND [date] > ', new DibiDateTime($timestamp)
);
// -> SELECT COUNT(*) as [count] FROM [comments] WHERE [ip] LIKE '192.168.%' AND [date] > 876693600
// dibi detects INSERT or REPLACE command
dibi::test('
REPLACE INTO products', array(
'title' => 'Super product',
'price' => 318,
'active' => TRUE,
));
// -> REPLACE INTO products ([title], [price], [active]) VALUES ('Super product', 318, 1)
// multiple INSERT command
$array = array(
'title' => 'Super Product',
'price' => 12,
'brand' => NULL,
'created' => new DateTime,
);
dibi::test('INSERT INTO products', $array, $array, $array);
// -> INSERT INTO products ([title], [price], [brand], [created]) VALUES ('Super Product', ...) , (...) , (...)
// dibi detects UPDATE command
dibi::test('
UPDATE colors SET', array(
'color' => 'blue',
'order' => 12,
), '
WHERE id=?', 123);
// -> UPDATE colors SET [color]='blue', [order]=12 WHERE id=123
// modifier applied to array
$array = array(1, 2, 3);
dibi::test('
SELECT *
FROM people
WHERE id IN (?)', $array
);
// -> SELECT * FROM people WHERE id IN ( 1, 2, 3 )
// modifier %by for ORDER BY
$order = array(
'field1' => 'asc',
'field2' => 'desc',
);
dibi::test('
SELECT *
FROM people
ORDER BY %by', $order, '
');
// -> SELECT * FROM people ORDER BY [field1] ASC, [field2] DESC
// indentifiers and strings syntax mix
dibi::test('UPDATE [table] SET `item` = "5 1/4"" diskette"');
// -> UPDATE [table] SET [item] = '5 1/4" diskette'

View File

@@ -1,46 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Result Set Data Types | dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
Tracy\Debugger::enable();
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// using manual hints
$res = dibi::query('SELECT * FROM [customers]');
$res->setType('customer_id', Dibi::INTEGER)
->setType('added', Dibi::DATETIME)
->setFormat(dibi::DATETIME, 'Y-m-d H:i:s');
Tracy\Dumper::dump($res->fetch());
// outputs:
// DibiRow(3) {
// customer_id => 1
// name => "Dave Lister" (11)
// added => "2007-03-11 17:20:03" (19)
// using auto-detection (works well with MySQL or other strictly typed databases)
$res = dibi::query('SELECT * FROM [customers]');
Tracy\Dumper::dump($res->fetch());
// outputs:
// DibiRow(3) {
// customer_id => 1
// name => "Dave Lister" (11)
// added => "2007-03-11 17:20:03" (19)

48
examples/sql-builder.php Normal file
View File

@@ -0,0 +1,48 @@
<pre>
<?php
require_once '../dibi/dibi.php';
// mysql
dibi::connect(array(
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
));
$arr1 = array(1, 2, 3);
$arr2 = array('one', 'two', 'three');
$arr3 = array(
'a' => 'one',
'b' => 'two',
'c' => 'three',
);
$arr4 = array(
'A' => 12,
'B' => NULL,
'C' => new TDateTime(31542),
'D' => 'string',
);
dibi::test(
"
SELECT *
FROM [test]
WHERE ([test.a] LIKE %T", '1995-03-01', "
OR [b1] IN (", $arr1, ")
OR [b2] IN (", $arr2, ")
OR [b3] IN (%N", $arr3, ")
OR [b4] IN %V", $arr4, "
AND [c] = 'embedded '' string'
OR [d]=%d", 10.3, "
OR [true]=", true, "
OR [false]=", false, "
OR [null]=", NULL, "
LIMIT 10");
?>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Tracy & SQL Exceptions | dibi</h1>
<p>Dibi can display and log exceptions via <a href="https://tracy.nette.org">Tracy</a>.</p>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
// enable Tracy
Tracy\Debugger::enable();
$connection = dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
'profiler' => array(
'run' => TRUE,
),
));
// add panel to debug bar
$panel = new Dibi\Bridges\Tracy\Panel;
$panel->register($connection);
// throws error because SQL is bad
dibi::query('SELECT FROM customers WHERE customer_id < ?', 38);

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<style> html { background: url(data/arrow.png) no-repeat bottom right; height: 100%; } </style>
<h1>Tracy | dibi</h1>
<p>Dibi can log queries and dump variables to the <a href="https://tracy.nette.org">Tracy</a>.</p>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
// enable Tracy
Tracy\Debugger::enable();
$connection = dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
'profiler' => array(
'run' => TRUE,
),
));
// add panel to debug bar
$panel = new Dibi\Bridges\Tracy\Panel;
$panel->register($connection);
// query will be logged
dibi::query('SELECT 123');
// result set will be dumped
Tracy\Debugger::barDump(dibi::fetchAll('SELECT * FROM customers WHERE customer_id < ?', 38), '[customers]');

View File

@@ -1,29 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using DateTime | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
// CHANGE TO REAL PARAMETERS!
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
'formatDate' => "'Y-m-d'",
'formatDateTime' => "'Y-m-d H-i-s'",
));
// generate and dump SQL
dibi::test('
INSERT INTO [mytable]', array(
'id' => 123,
'date' => new DateTime('12.3.2007'),
'stamp' => new DateTime('23.1.2007 10:23'),
)
);
// -> INSERT INTO [mytable] ([id], [date], [stamp]) VALUES (123, '2007-03-12', '2007-01-23 10-23-00')

View File

@@ -1,31 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Extension Methods | dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
Tracy\Debugger::enable();
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// using the "prototype" to add custom method to class DibiResult
DibiResult::extensionMethod('fetchShuffle', function (DibiResult $obj) {
$all = $obj->fetchAll();
shuffle($all);
return $all;
});
// fetch complete result set shuffled
$res = dibi::query('SELECT * FROM [customers]');
$all = $res->fetchShuffle();
Tracy\Dumper::dump($all);

View File

@@ -1,77 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Fluent Syntax | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
$id = 10;
$record = array(
'title' => 'Super product',
'price' => 318,
'active' => TRUE,
);
// SELECT ...
dibi::select('product_id')->as('id')
->select('title')
->from('products')
->innerJoin('orders')->using('(product_id)')
->innerJoin('customers USING (customer_id)')
->orderBy('title')
->test();
// -> SELECT [product_id] AS [id] , [title] FROM [products] INNER JOIN [orders]
// USING (product_id) INNER JOIN customers USING (customer_id) ORDER BY [title]
// SELECT ...
echo dibi::select('title')->as('id')
->from('products')
->fetchSingle();
// -> Chair (as result of query: SELECT [title] AS [id] FROM [products])
// INSERT ...
dibi::insert('products', $record)
->setFlag('IGNORE')
->test();
// -> INSERT IGNORE INTO [products] ([title], [price], [active]) VALUES ('Super product', 318, 1)
// UPDATE ...
dibi::update('products', $record)
->where('product_id = ?', $id)
->test();
// -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
// DELETE ...
dibi::delete('products')
->where('product_id = ?', $id)
->test();
// -> DELETE FROM [products] WHERE product_id = 10
// custom commands
dibi::command()
->update('products')
->where('product_id = ?', $id)
->set($record)
->test();
// -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
dibi::command()
->truncate('products')
->test();
// -> TRUNCATE [products]

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Limit & Offset | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// no limit
dibi::test('SELECT * FROM [products]');
// -> SELECT * FROM [products]
// with limit = 2
dibi::test('SELECT * FROM [products] %lmt', 2);
// -> SELECT * FROM [products] LIMIT 2
// with limit = 2, offset = 1
dibi::test('SELECT * FROM [products] %lmt %ofs', 2, 1);
// -> SELECT * FROM [products] LIMIT 2 OFFSET 1

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Logger | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
// enable query logging to this file
'profiler' => array(
'run' => TRUE,
'file' => 'data/log.sql',
),
));
try {
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] = ?', 1);
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < ?', 5);
$res = dibi::query('SELECT FROM [customers] WHERE [customer_id] < ?', 38);
} catch (DibiException $e) {
echo '<p>', get_class($e), ': ', $e->getMessage(), '</p>';
}
// outputs a log file
echo '<h2>File data/log.sql:</h2>';
echo '<pre>', file_get_contents('data/log.sql'), '</pre>';

View File

@@ -1,43 +0,0 @@
<?php ob_start() // needed by FirePHP ?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Profiler | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
'profiler' => array(
'run' => TRUE,
),
));
// execute some queries...
for ($i = 0; $i < 20; $i++) {
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < ?', $i);
}
// display output
?>
<p>Last query: <strong><?php echo dibi::$sql; ?></strong></p>
<p>Number of queries: <strong><?php echo dibi::$numOfQueries; ?></strong></p>
<p>Elapsed time for last query: <strong><?php echo sprintf('%0.3f', dibi::$elapsedTime * 1000); ?> ms</strong></p>
<p>Total elapsed time: <strong><?php echo sprintf('%0.3f', dibi::$totalTime * 1000); ?> ms</strong></p>
<br>
<p>Dibi can log to your Firebug Console. You first need to install the Firefox, Firebug and FirePHP extensions. You can install them from here:</p>
<ul>
<li>Firebug: https://addons.mozilla.org/en-US/firefox/addon/1843
<li>FirePHP: http://www.firephp.org/
</ul>

View File

@@ -1,53 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Substitutions | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
// create new substitution :blog: ==> wp_
dibi::getSubstitutes()->blog = 'wp_';
dibi::test('SELECT * FROM [:blog:items]');
// -> SELECT * FROM [wp_items]
// create new substitution :: (empty) ==> my_
dibi::getSubstitutes()->{''} = 'my_';
dibi::test("UPDATE ::table SET [text]='Hello World'");
// -> UPDATE my_table SET [text]='Hello World'
// create substitutions using fallback callback
function substFallBack($expr)
{
$const = 'SUBST_' . strtoupper($expr);
if (defined($const)) {
return constant($const);
} else {
throw new Exception("Undefined substitution :$expr:");
}
}
// define callback
dibi::getSubstitutes()->setCallback('substFallBack');
// define substitutes as constants
define('SUBST_ACCOUNT', 'eshop_');
define('SUBST_ACTIVE', 7);
dibi::test("
UPDATE :account:user
SET name='John Doe', status=:active:
WHERE id=", 7
);
// -> UPDATE eshop_user SET name='John Doe', status=7 WHERE id= 7

View File

@@ -1,34 +0,0 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Transactions | dibi</h1>
<?php
require __DIR__ . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
echo "<h2>Before</h2>\n";
dibi::query('SELECT * FROM [products]')->dump();
// -> 3 rows
dibi::begin();
dibi::query('INSERT INTO [products]', array(
'title' => 'Test product',
));
echo "<h2>After INSERT</h2>\n";
dibi::query('SELECT * FROM [products]')->dump();
dibi::rollback(); // or dibi::commit();
echo "<h2>After rollback</h2>\n";
dibi::query('SELECT * FROM [products]')->dump();
// -> 3 rows again

View File

@@ -1,55 +0,0 @@
Licenses
========
Good news! You may use Dibi under the terms of either the New BSD License
or the GNU General Public License (GPL) version 2 or 3.
The BSD License is recommended for most projects. It is easy to understand and it
places almost no restrictions on what you can do with the framework. If the GPL
fits better to your project, you can use the framework under this license.
You don't have to notify anyone which license you are using. You can freely
use Dibi in commercial projects as long as the copyright header
remains intact.
New BSD License
---------------
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of "Dibi" nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are
disclaimed. In no event shall the copyright owner or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused and on
any theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
GNU General Public License
--------------------------
GPL licenses are very very long, so instead of including them here we offer
you URLs with full text:
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)

271
license/license.gpl.cz.txt Normal file
View File

@@ -0,0 +1,271 @@
----------------------------------------------------------------------------------
Tento text je neofici<63>ln<6C>m p<>ekladem GNU General Public License (GNU GPL). Nebyl
vyd<EFBFBD>n nadac<61> Free Software Foundation a nevyjad<61>uje pr<70>vn<76> podstatu podm<64>nek pro
<EFBFBD><EFBFBD><EFBFBD>en<EFBFBD> softwaru pou<6F><75>vaj<61>c<EFBFBD>ho GNU GPL - tomuto <20><>elu slou<6F><75> v<>hradn<64> p<>vodn<64>
anglick<EFBFBD> verze GNU GPL. P<>esto douf<75>me, <20>e tento p<>eklad pom<6F><6D>e <20>esk<73>m <20>ten<65><6E><EFBFBD>m
l<EFBFBD>pe porozum<75>t licenci GNU GPL.
----------------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
<20>esk<73> p<>eklad verze 2, <20>erven 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Kop<6F>rov<6F>n<EFBFBD> a distribuce doslovn<76>ch kopi<70> tohoto licen<65>n<EFBFBD>ho dokumentu jsou
dovoleny komukoliv, jeho zm<7A>ny jsou v<>ak zak<61>z<EFBFBD>ny.
Preambule
Softwarov<6F> licence jsou v<>t<EFBFBD>inou navr<76>eny tak, <20>e v<>m odeb<65>raj<61> pr<70>vo svobodn<64>ho
sd<EFBFBD>len<EFBFBD> a <20>prav program<61>. Smyslem GNU General Public License je naproti tomu
zaru<EFBFBD>it svobodu ke sd<73>len<65> a <20>prav<61>m svobodn<64>ho softwaru - pro zaji<6A>t<EFBFBD>n<EFBFBD>
svobodn<EFBFBD>ho p<><70>stupu k tomuto softwaru pro v<>echny jeho u<>ivatele. Tato General
Public License se vztahuje na v<>t<EFBFBD>inu softwaru nadace Free Software Foundation a
na jak<61>koli jin<69> program, jeho<68> autor se p<>iklon<6F> k jej<65>mu pou<6F><75>v<EFBFBD>n<EFBFBD>. (N<>kter<65>
dal<EFBFBD><EFBFBD> software od Free Software Foundation je nam<61>sto toho pokryt GNU Lesser
General Public License.) M<><4D>ete ji rovn<76><6E> pou<6F><75>t pro sv<73> programy.
Pokud mluv<75>me o svobodn<64>m softwaru, m<>me na mysli svobodu, nikoliv cenu. Na<4E>e
General Public License je navr<76>ena pro zaji<6A>t<EFBFBD>n<EFBFBD> toho, <20>e m<><6D>ete svobodn<64> <20><><EFBFBD>it
kopie svobodn<64>ho softwaru (a <20><>tovat si poplatek za tuto slu<6C>bu, pokud chcete),
<EFBFBD>e obdr<64><72>te zdrojov<6F> k<>d anebo jej m<><6D>ete z<>skat, pokud ho chcete, <20>e m<><6D>ete
tento software modifikovat nebo jeho <20><>sti pou<6F><75>t v nov<6F>ch svobodn<64>ch programech;
a <20>e v<>te, <20>e tyto v<>ci sm<73>te d<>lat.
Abychom mohli va<76>e pr<70>va chr<68>nit, mus<75>me vytvo<76>it omezen<65>, kter<65> zak<61><6B><EFBFBD> komukoli
v<EFBFBD>m tato pr<70>va odep<65>rat nebo v<>s <20><>dat, abyste se t<>chto pr<70>v vzdal. Tato
omezen<EFBFBD> se prom<6F>taj<61> do jist<73>ch povinnost<73>, kter<65>m mus<75>te dost<73>t, pokud <20><><EFBFBD><EFBFBD>te
kopie doty<74>n<EFBFBD>ho softwaru anebo ho modifikujete.
Nap<61><70>klad, <20><><EFBFBD><EFBFBD>te-li kopie takov<6F>ho programu, a<> ji<6A> zdarma nebo za poplatek,
mus<EFBFBD>te poskytnout p<><70>jemc<6D>m v<>echna pr<70>va, kter<65> m<>te s<>m. Mus<75>te zaru<72>it, <20>e
p<EFBFBD><EFBFBD>jemci rovn<76><6E> dostanou anebo mohou z<>skat zdrojov<6F> k<>d. A mus<75>te jim uk<75>zat
tyto podm<64>nky, aby znali sv<73> pr<70>va.
Va<56>e pr<70>va chr<68>n<EFBFBD>me ve dvou kroc<6F>ch: (1) autorizac<61> softwaru a (2) nab<61>dkou t<>to
licence, kter<65> v<>m d<>v<EFBFBD> pr<70>voplatn<74> svolen<65> ke kop<6F>rov<6F>n<EFBFBD>, <20><><EFBFBD>en<65> a modifikaci
softwaru.
Kv<4B>li ochran<61> ka<6B>d<EFBFBD>ho autora i n<>s samotn<74>ch chceme zajistit, aby ka<6B>d<EFBFBD> ch<63>pal
skute<EFBFBD>nost, <20>e pro svobodn<64> software neplat<61> <20><>dn<64> z<>ruky. Je-li software n<>k<EFBFBD>m
jin<EFBFBD>m modifikov<6F>n a posl<73>n d<>le, chceme, aby p<><70>jemci v<>d<EFBFBD>li, <20>e to, co maj<61>,
nen<EFBFBD> origin<69>l, tak<61>e jak<61>koliv probl<62>my vnesen<65> jin<69>mi se neodraz<61> na reputaci
p<EFBFBD>vodn<EFBFBD>ch autor<6F>.
Kone<6E>n<EFBFBD>, ka<6B>d<EFBFBD> svobodn<64> program je neust<73>le ohro<72>en softwarov<6F>mi patenty.
P<EFBFBD>ejeme si zamezit nebezpe<70><65>, <20>e redistributo<74>i svobodn<64>ho programu obdr<64><72>
samostatn<EFBFBD> patentov<6F> osv<73>d<EFBFBD>en<65> a t<>m u<>in<69> program v<>zan<61>m. Abychom tomu
zamezili, deklarovali jsme, <20>e ka<6B>d<EFBFBD> patent mus<75> b<>t bu<62> vyd<79>n s t<>m, <20>e
umo<EFBFBD><EFBFBD>uje ka<6B>d<EFBFBD>mu svobodn<64> u<>it<69>, anebo nesm<73> b<>t vyd<79>n v<>bec.
P<>esn<73> ustanoven<65> a podm<64>nky pro kop<6F>rov<6F>n<EFBFBD>, <20><><EFBFBD>en<65> a modifikaci jsou uvedeny
d<EFBFBD>le.
USTANOVEN<45> A PODM<44>NKY PRO KOP<4F>ROV<4F>N<EFBFBD>, DISTRIBUCI A MODIFIKACI
0. Tato licence se vztahuje na kter<65>koliv program <20>i jin<69> d<>lo, kter<65> obsahuje
zm<EFBFBD>nku, um<75>st<73>nou v n<>m dr<64>itelem autorsk<73>ch pr<70>v, o tom, <20>e d<>lo m<><6D>e b<>t
<EFBFBD><EFBFBD><EFBFBD>eno podle ustanoven<65> GNU General Public License. V dal<61><6C>m textu znamen<65> "program"
ka<EFBFBD>d<EFBFBD> takov<6F> program nebo d<>lo a "d<>lo zalo<6C>en<65> na programu" znamen<65> bu<62> program
samotn<EFBFBD> anebo ka<6B>d<EFBFBD> jin<69> d<>lo z n<>j odvozen<65>, kter<65> podl<64>h<EFBFBD> autorsk<73>mu z<>konu:
t<EFBFBD>m se m<>n<EFBFBD> d<>lo obsahuj<75>c<EFBFBD> program nebo jeho <20><>st, bu<62> doslovn<76> anebo s
modifikacemi, pop<6F><70>pad<61> v p<>ekladu do jin<69>ho jazyka. (Nad<61>le je p<>eklad
zahrnov<EFBFBD>n bez omezen<65> pod pojem "modifikace".) Ka<4B>d<EFBFBD> u<>ivatel licence je
ozna<EFBFBD>ov<EFBFBD>n jako "vy".
Jin<EFBFBD> <20>innosti ne<6E> kop<6F>rov<6F>n<EFBFBD>, <20><><EFBFBD>en<65> a modifikace nejsou pokryty touto licenc<6E>;
sahaj<EFBFBD> mimo jej<65> r<>mec. Akt spu<70>t<EFBFBD>n<EFBFBD> programu nen<65> omezen a v<>stup z programu je
pokryt pouze tehdy, jestli<6C>e obsah v<>stupu tvo<76><6F> d<>lo zalo<6C>en<65> na programu (nez<65>visle
na tom, zda bylo vytvo<76>eno <20>innost<73> programu). Posouzen<65> platnosti p<>edchoz<6F>
v<EFBFBD>ty z<>vis<69> na tom, co program d<>l<EFBFBD>.
1. Sm<53>te kop<6F>rovat a <20><><EFBFBD>it doslovn<76> kopie zdrojov<6F>ho k<>du programu tak, jak jste
jej obdr<64>el a na libovoln<6C>m m<>diu, za p<>edpokladu, <20>e na ka<6B>d<EFBFBD> kopii viditeln<6C> a
n<EFBFBD>le<EFBFBD>it<EFBFBD> zve<76>ejn<6A>te zm<7A>nku o autorsk<73>ch pr<70>vech a absenci z<>ruky; ponech<63>te
nedot<EFBFBD>en<EFBFBD> v<>echny zm<7A>nky vztahuj<75>c<EFBFBD> se k t<>to licenci a k absenci z<>ruky; a d<>te
ka<EFBFBD>d<EFBFBD>mu p<><70>jemci spolu s programem kopii t<>to licence.
Za fyzick<63> akt p<>enesen<65> kopie m<><6D>ete <20><>dat poplatek a podle vlastn<74>ho uv<75><76>en<65>
m<EFBFBD><EFBFBD>ete nab<61>dnout za poplatek z<>ru<72>n<EFBFBD> ochranu.
2. M<><4D>ete modifikovat va<76>i kopii <20>i kopie programu anebo kter<65>koliv jeho <20><>sti,
a tak vytvo<76>it d<>lo zalo<6C>en<65> na programu a kop<6F>rovat a roz<6F>i<EFBFBD>ovat takov<6F>
modifikace <20>i d<>lo podle podm<64>nek paragrafu 1 v<><76>e, za p<>edpokladu, <20>e spln<6C>te
v<EFBFBD>echny tyto podm<64>nky:
a) Modifikovan<61> soubory mus<75>te opat<61>it z<>etelnou zm<7A>nkou uv<75>d<EFBFBD>j<EFBFBD>c<EFBFBD>, <20>e jste
soubory zm<7A>nil a datum ka<6B>d<EFBFBD> zm<7A>ny.
b) Mus<75>te umo<6D>nit, aby jak<61>koliv v<>mi publikovan<61> <20>i roz<6F>i<EFBFBD>ovan<61> d<>lo, kter<65>
obsahuje zcela nebo z<><7A>sti program nebo jakoukoli jeho <20><>st, pop<6F><70>pad<61> je z
programu nebo jeho <20><>sti odvozeno, mohlo b<>t jako celek bezplatn<74> poskytnuto
ka<6B>d<EFBFBD> t<>et<65> osob<6F> v souladu s ustanoven<65>mi t<>to licence.
c) Pokud modifikovan<61> program pracuje norm<72>ln<6C> tak, <20>e <20>te interaktivn<76> povely,
mus<75>te zajistit, <20>e p<>i nejb<6A><62>n<EFBFBD>j<EFBFBD><6A>m zp<7A>sobu jeho spu<70>t<EFBFBD>n<EFBFBD> vytiskne nebo zobraz<61>
hl<68><6C>en<65> zahrnuj<75>c<EFBFBD> p<><70>slu<6C>nou zm<7A>nku o autorsk<73>m pr<70>vu a uvede, <20>e neexistuje
<20><>dn<64> z<>ruka (nebo p<><70>padn<64>, <20>e z<>ruku poskytujete vy), a <20>e u<>ivatel<65> mohou za
t<>chto podm<64>nek program redistribuovat, a mus<75> u<>ivateli sd<73>lit, jak<61>m zp<7A>sobem
m<><6D>e nahl<68>dnout do kopie t<>to licence. (V<>jimka: v p<><70>pad<61>, <20>e s<>m program je
interaktivn<76>, av<61>ak <20><>dn<64> takov<6F> hl<68><6C>en<65> nevypisuje, nepo<70>aduje se, aby va<76>e
d<>lo zalo<6C>en<65> na programu takov<6F> hl<68><6C>en<65> vypisovalo.)
Tyto po<70>adavky se vztahuj<75> k modifikovan<61>mu d<>lu jako celku. Pokud lze
identifikovat <20><>sti takov<6F>ho d<>la, kter<65> z<>ejm<6A> nejsou odvozeny z programu a
mohou b<>t samy o sob<6F> rozumn<6D> pova<76>ov<6F>ny za nez<65>visl<73> a samostatn<74> d<>la, pak se
tato licence a jej<65> ustanoven<65> nevztahuj<75> na tyto <20><>sti, jsou-li <20><><EFBFBD>eny jako
nez<EFBFBD>visl<EFBFBD> d<>la. Av<41>ak jakmile tyt<79><74> <20><>sti roz<6F>i<EFBFBD>ujete jako <20><>st celku, j<>m<EFBFBD> je
d<EFBFBD>lo zalo<6C>en<65> na programu, mus<75> b<>t roz<6F>i<EFBFBD>ov<6F>n<EFBFBD> tohoto celku pod<6F><64>zeno
ustanoven<EFBFBD>m t<>to licence tak, <20>e povolen<65> poskytnut<75> dal<61><6C>m u<>ivatel<65>m se
roz<EFBFBD><EFBFBD><EFBFBD><EFBFBD> na cel<65> d<>lo, tedy na v<>echny jeho <20><>sti bez ohledu na to, kdo kterou
<EFBFBD><EFBFBD>st napsal.
Smyslem tohoto paragrafu tedy nen<65> z<>sk<73>n<EFBFBD> pr<70>v na d<>lo zcela napsan<61> v<>mi ani
pop<EFBFBD>r<EFBFBD>n<EFBFBD> va<76>ich pr<70>v v<><76>i n<>mu; skute<74>n<EFBFBD>m smyslem je v<>kon pr<70>va na <20><>zen<65>
distribuce odvozen<65>ch nebo kolektivn<76>ch d<>l zalo<6C>en<65>ch na programu.
Pouh<EFBFBD> spojen<65> jin<69>ho d<>la, je<6A> nen<65> na programu zalo<6C>eno, s programem (anebo
d<EFBFBD>lem zalo<6C>en<65>m na programu) na pam<61><6D>ov<6F>m nebo distribu<62>n<EFBFBD>m m<>diu neuvazuje toto
jin<EFBFBD> d<>lo do p<>sobnosti t<>to licence.
3. M<><4D>ete kop<6F>rovat a roz<6F>i<EFBFBD>ovat program (nebo d<>lo na n<>m zalo<6C>en<65>, viz
paragraf 2) v objektov<6F> anebo spustiteln<6C> podob<6F> podle ustanoven<65> paragraf<61> 1 a
2 v<><76>e, pokud spln<6C>te n<>kterou z n<>sleduj<75>c<EFBFBD>ch n<>le<6C>itost<73>:
a) Doprovod<6F>te jej zdrojov<6F>m k<>dem ve strojov<6F> <20>iteln<6C> form<72>. Zdrojov<6F> k<>d mus<75>
b<>t roz<6F>i<EFBFBD>ov<6F>n podle ustanoven<65> paragraf<61> 1 a 2 v<><76>e, a to na m<>diu b<><62>n<EFBFBD>
pou<6F><75>van<61>m pro v<>m<EFBFBD>nu softwaru; nebo
b) Doprovod<6F>te jej p<>semnou nab<61>dkou s platnost<73> nejm<6A>n<EFBFBD> t<>i roky, podle n<><6E>
poskytnete jak<61>koli t<>et<65> stran<61>, za poplatek nep<65>evy<76>uj<75>c<EFBFBD> va<76>e v<>daje
vynalo<6C>en<65> na fyzickou v<>robou zdrojov<6F> distribuce, kompletn<74> strojov<6F> <20>itelnou
kopii odpov<6F>daj<61>c<EFBFBD>ho zdrojov<6F>ho k<>du, jen<65> mus<75> b<>t <20><><EFBFBD>en podle ustanoven<65>
paragraf<61> 1 a 2 v<><76>e na m<>diu b<><62>n<EFBFBD> pou<6F><75>van<61>m pro v<>m<EFBFBD>nu softwaru; nebo
c) Doprovod<6F>te jej informacemi, kter<65> jste dostal ohledn<64> nab<61>dky na poskytnut<75>
zdrojov<6F>ho k<>du. (Tato alternativa je povolena jen pro nekomer<65>n<EFBFBD> <20><><EFBFBD>en<65> a jenom
tehdy, pokud jste obdr<64>el program v objektov<6F>m nebo spustiteln<6C>m tvaru spolu s
takovou nab<61>dkou, v souladu s polo<6C>kou b v<><76>e.)
Zdrojov<EFBFBD> k<>d k d<>lu je nejvhodn<64>j<EFBFBD><6A> formou d<>la z hlediska jeho p<><70>padn<64>ch
modifikac<EFBFBD>. Pro d<>lo ve spustiteln<6C>m tvaru znamen<65> <20>pln<6C> zdrojov<6F> k<>d ve<76>ker<65>
zdrojov<EFBFBD> k<>d pro v<>echny moduly, kter<65> obsahuje, plus jak<61>koli dal<61><6C> soubory pro
definici rozhran<61>, plus d<>vkov<6F> soubory pot<6F>ebn<62> pro kompilaci a instalaci
spustiteln<EFBFBD>ho programu. Zvl<76><6C>tn<74> v<>jimkou jsou v<>ak ty softwarov<6F> komponenty,
kter<EFBFBD> jsou norm<72>ln<6C> <20><><EFBFBD>eny (bu<62> ve zdrojov<6F> nebo bin<69>rn<72> form<72>) s hlavn<76>mi
sou<EFBFBD><EFBFBD>stmi opera<72>n<EFBFBD>ho syst<73>mu, na n<>m<EFBFBD> spustiteln<6C> program b<><62><EFBFBD> (tj. s
p<EFBFBD>eklada<EFBFBD>em, j<>drem apod.). Tyto komponenty nemus<75> b<>t <20><><EFBFBD>eny se zdrojov<6F>m k<>dem,
pokud ov<6F>em komponenta sama nedoprov<6F>z<EFBFBD> spustitelnou podobu d<>la.
Je-li <20><><EFBFBD>en<65> objektov<6F>ho nebo spustiteln<6C>ho k<>du <20>in<69>no nab<61>dkou p<><70>stupu ke
kop<EFBFBD>rov<EFBFBD>n<EFBFBD> z ur<75>it<69>ho m<>sta, potom se za distribuci zdrojov<6F>ho k<>du po<70><6F>t<EFBFBD> i
nab<EFBFBD>dnut<EFBFBD> ekvivalentn<74>ho p<><70>stupu ke kop<6F>rov<6F>n<EFBFBD> zdrojov<6F>ho k<>du ze stejn<6A>ho
m<EFBFBD>sta, by<62> p<>itom nejsou t<>et<65> strany nuceny ke zkop<6F>rov<6F>n<EFBFBD> zdrojov<6F>ho k<>du
spolu s objektov<6F>m.
4. Nesm<73>te kop<6F>rovat, modifikovat, poskytovat sublicence anebo <20><><EFBFBD>it program
jin<EFBFBD>m zp<7A>sobem ne<6E> v<>slovn<76> uveden<65>m v t<>to licenci. Jak<61>koli jin<69> pokus o
kop<EFBFBD>rov<EFBFBD>n<EFBFBD>, modifikov<6F>n<EFBFBD>, poskytnut<75> sublicence anebo <20><><EFBFBD>en<65> programu je
neplatn<EFBFBD> a automaticky ukon<6F><6E> va<76>e pr<70>va dan<61> touto licenc<6E>. Strany, kter<65> od
v<EFBFBD>s obdr<64>ely kopie anebo pr<70>va v souladu s touto licenc<6E>, v<>ak nemaj<61> sv<73>
licence ukon<6F>eny, dokud se jim pln<6C> pod<6F>izuj<75>.
5. Nen<65> va<76><61> povinost<73> tuto licenci p<>ijmout, proto<74>e jste ji nepodepsal. Nic
jin<EFBFBD>ho v<>m v<>ak ned<65>v<EFBFBD> mo<6D>nost kop<6F>rovat nebo <20><><EFBFBD>it program nebo odvozen<65> d<>la.
V p<><70>pad<61>, <20>e tuto licenci nep<65>ijmete, jsou tyto <20>innosti z<>konem zak<61>z<EFBFBD>ny. T<>m
p<EFBFBD>dem modifikac<61> anebo <20><><EFBFBD>en<65>m programu (anebo ka<6B>d<EFBFBD>ho d<>la zalo<6C>en<65>ho na
programu) vyjad<61>ujete sv<73> pod<6F><64>zen<65> se licenci a v<>em jej<65>m ustanoven<65>m a
podm<EFBFBD>nk<EFBFBD>m pro kop<6F>rovan<61>, modifikov<6F>n<EFBFBD> a <20><><EFBFBD>en<65> programu a d<>l na n<>m zalo<6C>en<65>ch.
6. Poka<6B>d<EFBFBD>, kdy<64> redistribuujete program (nebo d<>lo zalo<6C>en<65> na programu),
z<EFBFBD>sk<EFBFBD>v<EFBFBD> p<><70>jemce od p<>vodn<64>ho dr<64>itele licence pr<70>vo kop<6F>rovat, modifikovat a
<EFBFBD><EFBFBD><EFBFBD>it program v souladu s t<>mito ustanoven<65>mi a podm<64>nkami. Nesm<73>te kl<6B>st <20><>dn<64>
dal<EFBFBD><EFBFBD> p<>ek<65><6B>ky v<>konu zde zaru<72>en<65>ch p<><70>jemcov<6F>ch pr<70>v. Nejste odpov<6F>dn<64> za
vym<EFBFBD>h<EFBFBD>n<EFBFBD> dodr<64>ov<6F>n<EFBFBD> t<>to licence t<>et<65>mi stranami.
7. Jsou-li v<>m z rozhodnut<75> soudu, obvin<69>n<EFBFBD>m z poru<72>en<65> patentu nebo z
jak<EFBFBD>hokoli jin<69>ho d<>vodu (nejen v souvislosti s patenty) ulo<6C>eny takov<6F> podm<64>nky
(a<> ji<6A> p<><70>kazem soudu, smlouvou nebo jinak), kter<65> se vylu<6C>uj<75> s podm<64>nkami
t<EFBFBD>to licence, nejste t<>m osvobozen od podm<64>nek t<>to licence. Pokud nem<65><6D>ete
<EFBFBD><EFBFBD><EFBFBD>it program tak, abyste vyhov<6F>l z<>rove<76> sv<73>m z<>vazk<7A>m vypl<70>vaj<61>c<EFBFBD>m z t<>to
licence a jin<69>m platn<74>m z<>vazk<7A>m, nesm<73>te jej v d<>sledku toho <20><><EFBFBD>it v<>bec. Pokud
by nap<61><70>klad patentov<6F> osv<73>d<EFBFBD>en<65> nepovolovalo bezplatnou redistribuci programu
v<EFBFBD>emi, kdo va<76><61>m p<>i<EFBFBD>in<69>n<EFBFBD>m z<>skaj<61> p<><70>mo nebo nep<65><70>mo jeho kopie, pak by jedin<69>
mo<EFBFBD>n<EFBFBD> zp<7A>sob jak vyhov<6F>t z<>rove<76> patentov<6F>mu osv<73>d<EFBFBD>en<65> i t<>to licenci spo<70><6F>val v
ukon<EFBFBD>en<EFBFBD> distribuce programu.
Pokud by se za n<>jak<61>ch specifick<63>ch okolnost<73> jevila n<>kter<65> <20><>st tohoto
paragrafu jako neplatn<74> nebo nevynutiteln<6C>, pova<76>uje se za sm<73>rodatnou rovnov<6F>ha
vyj<EFBFBD>d<EFBFBD>en<EFBFBD> t<>mto paragrafem a paragraf jako celek se pova<76>uje za sm<73>rodatn<74> za
jin<EFBFBD>ch okolnost<73>.
Smyslem tohoto paragrafu nen<65> nav<61>d<EFBFBD>t v<>s k poru<72>ov<6F>n<EFBFBD> patent<6E> <20>i jin<69>ch
ustanoven<EFBFBD> vlastnick<63>ho pr<70>va, anebo tato ustanoven<65> zpochyb<79>ovat; jedin<69>m jeho
smyslem je ochrana integrity syst<73>mu <20><><EFBFBD>en<65> svobodn<64>ho softwaru, kter<65> je
podlo<EFBFBD>en ve<76>ejn<6A>mi licen<65>n<EFBFBD>mi p<>edpisy. Mnoz<6F> lid<69> poskytli sv<73> p<><70>sp<73>vky do
<EFBFBD>irok<EFBFBD>ho okruhu softwaru <20><><EFBFBD>en<65>ho t<>mto syst<73>mem, spolehnuv<75>e se na jeho
d<EFBFBD>sledn<EFBFBD> uplat<61>ov<6F>n<EFBFBD>; z<>le<6C><65> na autorovi/d<>rci, aby rozhodl, zda si p<>eje <20><><EFBFBD>it
software pomoc<6F> n<>jak<61>ho jin<69>ho syst<73>mu a <20><>dn<64> u<>ivatel licence nem<65><6D>e takov<6F>
rozhodnut<EFBFBD> zpochyb<79>ovat.
Smyslem tohoto paragrafu je zevrubn<62> osv<73>tlit to, co je pova<76>ov<6F>no za d<>sledek
plynouc<EFBFBD> ze zbytku t<>to licence.
8. Pokud je <20><><EFBFBD>en<65> <20>i pou<6F>it<69> programu v n<>kter<65>ch zem<65>ch omezeno bu<62> patenty
anebo autorsky chr<68>n<EFBFBD>n<EFBFBD>mi rozhran<61>mi, m<><6D>e dr<64>itel p<>vodn<64>ch autorsk<73>ch pr<70>v,
kter<EFBFBD> sv<73><76>uje program do p<>sobnosti t<>to licence, p<>idat v<>slovn<76> omezen<65> pro
geografick<EFBFBD> <20><><EFBFBD>en<65>, vylu<6C>uj<75>c<EFBFBD> takov<6F> zem<65>, tak<61>e <20><><EFBFBD>en<65> je povoleno jen v t<>ch
zem<EFBFBD>ch nebo mezi t<>mi zem<65>mi, kter<65> nejsou t<>mto zp<7A>sobem vylou<6F>eny. Tato
licence zahrnuje v tomto p<><70>pad<61> takov<6F> omezen<65> p<>esn<73> tak, jako by bylo zaps<70>no
v textu t<>to licence.
9. Free Software Foundation m<><6D>e <20>as od <20>asu vyd<79>vat upraven<65> nebo nov<6F> verze
General Public License. Takov<6F> nov<6F> verze se budou sv<73>m duchem podobat sou<6F>asn<73>
verzi, v jednotlivostech se v<>ak mohou li<6C>it s ohledem na nov<6F> probl<62>my <20>i z<>jmy.
Ka<EFBFBD>d<EFBFBD> verzi je p<>id<69>leno rozli<6C>uj<75>c<EFBFBD> <20><>slo verze. Pokud program specifikuje
<EFBFBD><EFBFBD>slo verze, kter<65> se na n<>j vztahuje, a "v<>echny n<>sleduj<75>c<EFBFBD> verze", m<><6D>ete se
podle uv<75><76>en<65> <20><>dit ustanoven<65>mi a podm<64>nkami bu<62>to on<6F> konkr<6B>tn<74> verze anebo
kter<EFBFBD>koliv n<>sleduj<75>c<EFBFBD> verze, kterou vydala Free Software Foundation. Jestli<6C>e
program nespecifikuje <20><>slo verze t<>to licence, m<><6D>ete si vybrat libovolnou
verzi, kterou kdy Free Software Foundation vydala.
10. Pokud si p<>ejete zahrnout <20><>sti programu do jin<69>ch svobodn<64>ch program<61>,
jejich<EFBFBD> distribu<62>n<EFBFBD> podm<64>nky jsou odli<6C>n<EFBFBD>, za<7A>lete autorovi <20><>dost o povolen<65>. V
p<EFBFBD><EFBFBD>pad<EFBFBD> softwaru, k n<>mu<6D> vlastn<74> autorsk<73> pr<70>va Free Software Foundation,
napi<EFBFBD>te Free Software Foundation; n<>kdy <20>in<69>me v<>jimky ze zde uveden<65>ch
ustanoven<EFBFBD>. Na<4E>e rozhodnut<75> bude vedeno dv<64>ma c<>li: zachov<6F>n<EFBFBD>m svobodn<64> povahy
v<EFBFBD>ech odvozenin na<6E>eho svobodn<64>ho softwaru a podporou sd<73>len<65> a op<6F>tovn<76>ho
vyu<EFBFBD>it<EFBFBD> softwaru obecn<63>.
Z<>RUKA SE NEPOSKYTUJE
11. VZHLEDEM K BEZPLATN<54>MU POSKYTNUT<55> LICENCE K PROGRAMU SE NA PROGRAM
NEVZTAHUJE <20><>DN<44> Z<>RUKA, A TO V M<><4D>E POVOLEN<45> PLATN<54>M Z<>KONEM. POKUD NEN<45>
P<EFBFBD>SEMN<EFBFBD> STANOVENO JINAK, POSKYTUJ<55> DR<44>ITEL<45> AUTORSK<53>CH PR<50>V POP<4F><50>PAD<41> JIN<49>
STRANY PROGRAM "TAK, JAK JE", BEZ Z<>RUKY JAK<41>HOKOLI DRUHU, A<> V<>SLOVN<56> NEBO
VYPL<EFBFBD>VAJ<EFBFBD>C<EFBFBD>, V<>ETN<54>, ALE NIKOLI JEN, Z<>RUK PRODEJNOSTI A VHODNOSTI PRO UR<55>IT<49>
<EFBFBD><EFBFBD>EL. POKUD JDE O KVALITU A V<>KONNOST PROGRAMU, LE<4C><45> VE<56>KER<45> RIZIKO NA V<>S.
POKUD BY SE U PROGRAMU PROJEVILY Z<>VADY, PADAJ<41> N<>KLADY ZA V<>ECHNU POT<4F>EBNOU
<EFBFBD>DR<EFBFBD>BU, OPRAVU <20>I N<>PRAVU NA V<><56> VRUB.
12. V <20><>DN<44>M P<><50>PAD<41>, S V<>JIMKOU TOHO, KDY<44> TO VY<56>ADUJE PLATN<54> Z<>KON, ANEBO KDY<44>
TO BYLO P<>SEMN<4D> ODSOUHLASENO, V<>M NEBUDE <20><>DN<44> Z DR<44>ITEL<45> AUTORSK<53>CH PR<50>V ANI
<EFBFBD><EFBFBD>DN<EFBFBD> JIN<49> STRANA, KTER<45> SM<53> MODIFIKOVAT <20>I <20><><EFBFBD>IT PROGRAM V SOULADU S
P<EFBFBD>EDCHOZ<EFBFBD>MI USTANOVEN<45>MI, ODPOV<4F>DNI ZA <20>KODY, V<>ETN<54> V<>ECH OBECN<43>CH, SPECI<43>LN<4C>CH,
NAHODIL<EFBFBD>CH NEBO N<>SLEDN<44>CH <20>KOD VYPL<50>VAJ<41>C<EFBFBD>CH Z U<><55>V<EFBFBD>N<EFBFBD> ANEBO NESCHOPNOSTI
U<EFBFBD><EFBFBD>VAT PROGRAMU (V<>ETN<54>, ALE NIKOLI JEN, ZTR<54>TY NEBO ZKRESLEN<45> DAT, NEBO
TRVAL<EFBFBD>CH <20>KOD ZP<5A>SOBEN<45>CH V<>M NEBO T<>ET<45>M STRAN<41>M, NEBO SELH<4C>N<EFBFBD> FUNKCE PROGRAMU
V SOU<4F>INNOSTI S JIN<49>MI PROGRAMY), A TO I V P<><50>PAD<41>, <20>E TAKOV<4F> DR<44>ITEL AUTORSK<53>CH
PR<EFBFBD>V NEBO JIN<49> STRANA BYLI UPOZORN<52>NI NA MO<4D>NOST TAKOV<4F>CH <20>KOD.
KONEC USTANOVEN<45> A PODM<44>NEK
----------------------------------------------------------------------------------
(c) 2004, Str<74>nky o svobodn<64>m software (info@gnu.cz)
Tento p<>eklad je z velk<6C> <20><>sti zalo<6C>en na p<>ekladu od Ladislava Lhotky.
V p<><70>pad<61> dopl<70>uj<75>c<EFBFBD>ch informac<61> nebo oprav kontaktujte maintainera: kysela@gnu.cz
Posledn<EFBFBD> <20>prava: 22. 12. 2004
----------------------------------------------------------------------------------

279
license/license.gpl.txt Normal file
View File

@@ -0,0 +1,279 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

129
readme.md
View File

@@ -1,129 +0,0 @@
[Dibi](http://dibiphp.com) - smart database layer for PHP [![Buy me a coffee](https://files.nette.org/images/coffee1s.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9XXL5ZJHAYQUN)
=========================================================
[![Downloads this Month](https://img.shields.io/packagist/dm/dibi/dibi.svg)](https://packagist.org/packages/dibi/dibi)
Database access functions in PHP are not standardised. This library
hides the differences between them, and above all, it gives you a very handy interface.
The best way to install Dibi is to use a [Composer](https://getcomposer.org/download):
php composer.phar require dibi/dibi
Or you can download the latest package from http://dibiphp.com. In this
package is also `Dibi.minified`, shrinked single-file version of whole Dibi,
useful when you don't want to modify the library, but just use it.
Dibi requires PHP 5.2.0 or later. It has been tested with PHP 5.5 too.
Examples
--------
Refer to the `examples` directory for examples. Dibi documentation is
available on the [homepage](http://dibiphp.com).
Connect to database:
```php
// connect to database (static way)
dibi::connect(array(
'driver' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
));
// or object way; in all other examples use $connection-> instead of dibi::
$connection = new DibiConnection($options);
```
SELECT, INSERT, UPDATE
```php
dibi::query('SELECT * FROM users WHERE id = ?', $id);
$arr = array(
'name' => 'John',
'is_admin' => TRUE,
);
dibi::query('INSERT INTO users', $arr);
// INSERT INTO users (`name`, `is_admin`) VALUES ('John', 1)
dibi::query('UPDATE users SET', $arr, 'WHERE `id`=?', $x);
// UPDATE users SET `name`='John', `is_admin`=1 WHERE `id` = 123
dibi::query('UPDATE users SET', array(
'title' => array('SHA1(?)', 'tajneheslo'),
));
// UPDATE users SET 'title' = SHA1('tajneheslo')
```
Getting results
```php
$result = dibi::query('SELECT * FROM users');
$value = $result->fetchSingle(); // single value
$all = $result->fetchAll(); // all rows
$assoc = $result->fetchAssoc('id'); // all rows as associative array
$pairs = $result->fetchPairs('customerID', 'name'); // all rows as key => value pairs
// iterating
foreach ($result as $n => $row) {
print_r($row);
}
```
Modifiers for arrays:
```php
dibi::query('SELECT * FROM users WHERE %and', array(
array('number > ?', 10),
array('number < ?', 100),
));
// SELECT * FROM users WHERE (number > 10) AND (number < 100)
```
<table>
<tr><td> %and </td><td> </td><td> `[key]=val AND [key2]="val2" AND ...` </td></tr>
<tr><td> %or </td><td> </td><td> `[key]=val OR [key2]="val2" OR ...` </td></tr>
<tr><td> %a </td><td> assoc </td><td> `[key]=val, [key2]="val2", ...` </td></tr>
<tr><td> %l %in </td><td> list </td><td> `(val, "val2", ...)` </td></tr>
<tr><td> %v </td><td> values </td><td> `([key], [key2], ...) VALUES (val, "val2", ...)` </td></tr>
<tr><td> %m </td><td> multivalues </td><td> `([key], [key2], ...) VALUES (val, "val2", ...), (val, "val2", ...), ...` </td></tr>
<tr><td> %by </td><td> ordering </td><td> `[key] ASC, [key2] DESC ...` </td></tr>
<tr><td> %n </td><td> identifiers </td><td> `[key], [key2] AS alias, ...` </td></tr>
<tr><td> other </td><td> - </td><td> `val, val2, ...` </td></tr>
</table>
Modifiers for LIKE
```php
dibi::query("SELECT * FROM table WHERE name LIKE %like~", $query);
```
<table>
<tr><td> %like~ </td><td> begins with </td></tr>
<tr><td> %~like </td><td> ends with </td></tr>
<tr><td> %~like~ </td><td> contains </td></tr>
</table>
DateTime:
```php
dibi::query('UPDATE users SET', array(
'time' => new DateTime,
));
// UPDATE users SET ('2008-01-01 01:08:10')
```
Testing:
```php
echo dibi::$sql; // last SQL query
echo dibi::$elapsedTime;
echo dibi::$numOfQueries;
echo dibi::$totalTime;
```

View File

@@ -1,70 +0,0 @@
<?php
use Tester\Assert;
require __DIR__ . '/bootstrap.php';
class TestClass extends DibiObject
{
public function getBar()
{
return 123;
}
public function isFoo()
{
return 456;
}
}
// calling
Assert::exception(function () {
$obj = new TestClass;
$obj->undeclared();
}, 'LogicException', 'Call to undefined method TestClass::undeclared().');
Assert::exception(function () {
TestClass::undeclared();
}, 'LogicException', 'Call to undefined static method TestClass::undeclared().');
// writing
Assert::exception(function () {
$obj = new TestClass;
$obj->undeclared = 'value';
}, 'LogicException', 'Cannot assign to an undeclared property TestClass::$undeclared.');
// property getter
$obj = new TestClass;
Assert::true(isset($obj->bar));
Assert::same(123, $obj->bar);
Assert::false(isset($obj->foo));
Assert::same(456, $obj->foo);
// reading
Assert::exception(function () {
$obj = new TestClass;
$val = $obj->undeclared;
}, 'LogicException', 'Cannot read an undeclared property TestClass::$undeclared.');
// unset/isset
Assert::exception(function () {
$obj = new TestClass;
unset($obj->undeclared);
}, 'LogicException', 'Cannot unset the property TestClass::$undeclared.');
Assert::false(isset($obj->undeclared));
// extension method
TestClass::extensionMethod('join', $func = function (TestClass $that, $separator) {
return $that->foo . $separator . $that->bar;
});
$obj = new TestClass;
Assert::same('456*123', $obj->join('*'));

View File

@@ -1 +0,0 @@
Dibi 2.2.3 (released on 2015-01-13)