mirror of
https://github.com/dg/dibi.git
synced 2025-08-30 09:19:48 +02:00
Compare commits
160 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
da09733a3d | ||
|
901dc76103 | ||
|
8d063fe0a1 | ||
|
a2d0d66d0f | ||
|
7565ffb1d4 | ||
|
318b3093a5 | ||
|
7a6cdc8afa | ||
|
ab892255d3 | ||
|
e221a13dda | ||
|
56628144b4 | ||
|
32dd3969a3 | ||
|
1e33b67e37 | ||
|
3e04378375 | ||
|
ae77148773 | ||
|
b0f155f767 | ||
|
fc69f8f47b | ||
|
44f281de27 | ||
|
9eddba204f | ||
|
9b84459f09 | ||
|
8c4211d5be | ||
|
96c69f5bed | ||
|
398c7a3500 | ||
|
e5af8a8c67 | ||
|
f935968aa7 | ||
|
52d2ecf5b0 | ||
|
d4f9e0378f | ||
|
360f8799cf | ||
|
119d5a1995 | ||
|
c438b72972 | ||
|
97f2ed392f | ||
|
e48cd54a41 | ||
|
85d190ec05 | ||
|
c0bd3761de | ||
|
7f0fa2e75e | ||
|
69ead6da56 | ||
|
41e5b32a22 | ||
|
2a4f5ec456 | ||
|
d12895102f | ||
|
4e41f1641e | ||
|
c23bf15a3d | ||
|
3728b16a21 | ||
|
69876a70b7 | ||
|
4334eaa963 | ||
|
a8acce6d59 | ||
|
b27b0193f1 | ||
|
40e9f313c3 | ||
|
7bb5684d71 | ||
|
fd22c55639 | ||
|
62f8c47410 | ||
|
11a314ca96 | ||
|
c8febb8322 | ||
|
24bf999cd9 | ||
|
2632953541 | ||
|
1459c6c95d | ||
|
2f9704bca2 | ||
|
8da9e778a6 | ||
|
89dfa9f772 | ||
|
18e02de80c | ||
|
f6b781f12d | ||
|
c41167d49f | ||
|
5c045e58dc | ||
|
da0a239d6d | ||
|
de4a882788 | ||
|
041f059408 | ||
|
2c8906e7c4 | ||
|
dfacb48449 | ||
|
7d964e054b | ||
|
cbd37021f2 | ||
|
1aad1c8da9 | ||
|
1a9abfb326 | ||
|
a0febd3d50 | ||
|
c8fedf7692 | ||
|
7c6947a019 | ||
|
3f42b2cf55 | ||
|
981a1adaad | ||
|
58ed8d34f4 | ||
|
cbb315cbc7 | ||
|
c174e20135 | ||
|
6bfa40f594 | ||
|
0eeff53fe8 | ||
|
40444c1341 | ||
|
d19eb5b815 | ||
|
46850aa588 | ||
|
89c53395c1 | ||
|
22c27f678a | ||
|
ea00d5d37d | ||
|
5ee6a19f93 | ||
|
fd1d2b86ff | ||
|
9ff43d0ac3 | ||
|
8a6d664876 | ||
|
6492fe10b6 | ||
|
8b99c00f91 | ||
|
25fa4293fc | ||
|
453cc9be13 | ||
|
917b0851da | ||
|
6856ace01e | ||
|
330930fb34 | ||
|
39c62c1cd5 | ||
|
879bbeba1f | ||
|
eb5b3d9756 | ||
|
ccea418c34 | ||
|
d35a850311 | ||
|
0d8478d1d3 | ||
|
281cdb65e0 | ||
|
53874f22d4 | ||
|
d5e6cedddb | ||
|
6f4d2c545d | ||
|
0ff0cd21df | ||
|
5243122e6a | ||
|
7f995a558b | ||
|
05b8c0ad43 | ||
|
2c6608f817 | ||
|
8b89eb3bd0 | ||
|
609a3d64fb | ||
|
5f4dbbbcfd | ||
|
a7ddc1547c | ||
|
5ffbe076f3 | ||
|
e2e5ba16f1 | ||
|
c7dbc7134c | ||
|
e33689a5a1 | ||
|
89a7c8ac73 | ||
|
7452065de0 | ||
|
f766827219 | ||
|
d03f60c43c | ||
|
7c693a26fb | ||
|
799dfcc65e | ||
|
b7834a3373 | ||
|
af7c4de14a | ||
|
166f716091 | ||
|
57fa5831b1 | ||
|
e834c0ccae | ||
|
89ee302927 | ||
|
53178717ad | ||
|
48ea525b04 | ||
|
f64a5d5251 | ||
|
4d2c90ba68 | ||
|
4b2e04220b | ||
|
0c86515076 | ||
|
a2b1036a66 | ||
|
6536dfb7dd | ||
|
ac980fe8c9 | ||
|
3b8766d376 | ||
|
f447a03c96 | ||
|
11b294be44 | ||
|
d705f4089d | ||
|
da608c2db2 | ||
|
da70be27a8 | ||
|
6c4ede17d6 | ||
|
36b88503f9 | ||
|
2cc9fa22fb | ||
|
82e82e8872 | ||
|
deeff32be2 | ||
|
b779082ed9 | ||
|
1e3728c582 | ||
|
3030881f07 | ||
|
18d3dd444d | ||
|
0e7f85c73a | ||
|
a3a17f1c55 | ||
|
0951ea574c | ||
|
8361028ff3 |
@@ -1,21 +0,0 @@
|
||||
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
|
@@ -1,33 +0,0 @@
|
||||
<?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;}}}?>
|
40
dibi/Nette/IDebuggable.php
Normal file
40
dibi/Nette/IDebuggable.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Nette Framework
|
||||
*
|
||||
* Copyright (c) 2004, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "Nette license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://nettephp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2004, 2008 David Grudl
|
||||
* @license http://nettephp.com/license Nette license
|
||||
* @link http://nettephp.com
|
||||
* @category Nette
|
||||
* @package Nette
|
||||
*/
|
||||
|
||||
/*namespace Nette;*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Custom output for Nette::Debug.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2004, 2008 David Grudl
|
||||
* @package Nette
|
||||
*/
|
||||
interface IDebuggable
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns custom panels.
|
||||
* @return array
|
||||
*/
|
||||
function getPanels();
|
||||
|
||||
}
|
1136
dibi/dibi.php
1136
dibi/dibi.php
File diff suppressed because it is too large
Load Diff
397
dibi/drivers/mssql.php
Normal file
397
dibi/drivers/mssql.php
Normal file
@@ -0,0 +1,397 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for MS SQL database.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'host' - the MS SQL server host name. It can also include a port number (hostname:port)
|
||||
* - 'username' (or 'user')
|
||||
* - 'password' (or 'pass')
|
||||
* - 'persistent' - try to find a persistent link?
|
||||
* - 'database' - the database name to select
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiMsSqlDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var resource Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var resource Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('mssql')) {
|
||||
throw new DibiDriverException("PHP extension 'mssql' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
DibiConnection::alias($config, 'username', 'user');
|
||||
DibiConnection::alias($config, 'password', 'pass');
|
||||
DibiConnection::alias($config, 'host', 'hostname');
|
||||
|
||||
if (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($config['database'], $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 IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
$this->resultSet = @mssql_query($sql, $this->connection); // intentionally @
|
||||
|
||||
if ($this->resultSet === FALSE) {
|
||||
throw new DibiDriverException('Query error', 0, $sql);
|
||||
}
|
||||
|
||||
return is_resource($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
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 insertId($sequence)
|
||||
{
|
||||
throw new NotSupportedException('MS SQL does not support autoincrementing.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->query('BEGIN TRANSACTION');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->query('COMMIT');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->query('ROLLBACK');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
case dibi::FIELD_BINARY:
|
||||
return "'" . str_replace("'", "''", $value) . "'";
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
// @see http://msdn.microsoft.com/en-us/library/ms176027.aspx
|
||||
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
|
||||
return '[' . str_replace('.', '].[', $value) . ']';
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? -1 : 0;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("'Y-m-d'", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("'Y-m-d H:i:s'", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
// offset suppot is missing...
|
||||
if ($limit >= 0) {
|
||||
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
|
||||
}
|
||||
|
||||
if ($offset) {
|
||||
throw new NotImplementedException('Offset is not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
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
|
||||
* @internal
|
||||
*/
|
||||
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
|
||||
* @throws DibiException
|
||||
*/
|
||||
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 getColumnsMeta()
|
||||
{
|
||||
$count = mssql_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$row = (array) mssql_fetch_field($this->resultSet, $i);
|
||||
$res[] = array(
|
||||
'name' => $row['name'],
|
||||
'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'],
|
||||
'table' => $row['column_source'],
|
||||
'nativetype' => $row['type'],
|
||||
);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
@@ -1,341 +1,494 @@
|
||||
<?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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for MySQL database.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'host' - the MySQL server host name
|
||||
* - 'port' - the port number to attempt to connect to the MySQL server
|
||||
* - 'socket' - the socket or named pipe
|
||||
* - 'username' (or 'user')
|
||||
* - 'password' (or 'pass')
|
||||
* - 'persistent' - try to find a persistent link?
|
||||
* - 'database' - the database name to select
|
||||
* - 'charset' - character encoding to set
|
||||
* - 'unbuffered' - sends query without fetching and buffering the result rows automatically?
|
||||
* - 'options' - driver specific constants (MYSQL_*)
|
||||
* - 'sqlmode' - see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiMySqlDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var resource Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var resource Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
/** @var bool Is buffered (seekable and countable)? */
|
||||
private $buffered;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('mysql')) {
|
||||
throw new DibiDriverException("PHP extension 'mysql' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
DibiConnection::alias($config, 'username', 'user');
|
||||
DibiConnection::alias($config, 'password', 'pass');
|
||||
DibiConnection::alias($config, 'host', 'hostname');
|
||||
DibiConnection::alias($config, 'options');
|
||||
|
||||
// default values
|
||||
if (!isset($config['username'])) $config['username'] = ini_get('mysql.default_user');
|
||||
if (!isset($config['password'])) $config['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['options']); // intentionally @
|
||||
} else {
|
||||
$this->connection = @mysql_pconnect($host, $config['username'], $config['password'], $config['options']); // 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) {
|
||||
$ok = @mysql_query("SET NAMES '$config[charset]'", $this->connection); // intentionally @
|
||||
if (!$ok) {
|
||||
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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'])) {
|
||||
if (!@mysql_query("SET sql_mode='$config[sqlmode]'", $this->connection)) { // intentionally @
|
||||
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection));
|
||||
}
|
||||
}
|
||||
|
||||
$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 IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
if ($this->buffered) {
|
||||
$this->resultSet = @mysql_query($sql, $this->connection); // intentionally @
|
||||
} else {
|
||||
$this->resultSet = @mysql_unbuffered_query($sql, $this->connection); // intentionally @
|
||||
}
|
||||
|
||||
if (mysql_errno($this->connection)) {
|
||||
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection), $sql);
|
||||
}
|
||||
|
||||
return is_resource($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
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 insertId($sequence)
|
||||
{
|
||||
return mysql_insert_id($this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->query('START TRANSACTION');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->query('COMMIT');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->query('ROLLBACK');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
case dibi::FIELD_BINARY:
|
||||
return "'" . mysql_real_escape_string($value, $this->connection) . "'";
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
// @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
|
||||
$value = str_replace('`', '``', $value);
|
||||
return '`' . str_replace('.', '`.`', $value) . '`';
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? 1 : 0;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("'Y-m-d'", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("'Y-m-d H:i:s'", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
if ($limit < 0 && $offset < 1) return;
|
||||
|
||||
// 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**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
if (!$this->buffered) {
|
||||
throw new DibiDriverException('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
|
||||
* @internal
|
||||
*/
|
||||
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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function seek($row)
|
||||
{
|
||||
if (!$this->buffered) {
|
||||
throw new DibiDriverException('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 getColumnsMeta()
|
||||
{
|
||||
$count = mysql_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$row = (array) mysql_fetch_field($this->resultSet, $i);
|
||||
$res[] = array(
|
||||
'name' => $row['name'],
|
||||
'table' => $row['table'],
|
||||
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
|
||||
'nativetype' => strtoupper($row['type']),
|
||||
'vendor' => $row,
|
||||
);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
$this->query("SHOW FULL TABLES");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(FALSE)) {
|
||||
$res[] = array(
|
||||
'name' => $row[0],
|
||||
'view' => isset($row[1]) && $row[1] === 'VIEW',
|
||||
);
|
||||
}
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
$this->query("SHOW COLUMNS FROM `$table`");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$type = explode('(', $row['Type']);
|
||||
$res[] = array(
|
||||
'name' => $row['Field'],
|
||||
'table' => $table,
|
||||
'nativetype' => strtoupper($type[0]),
|
||||
'size' => isset($type[1]) ? (int) $type[1] : NULL,
|
||||
'nullable' => $row['Null'] === 'YES',
|
||||
'default' => $row['Default'],
|
||||
'autoincrement' => $row['Extra'] === 'auto_increment',
|
||||
);
|
||||
}
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
$this->query("SHOW INDEX FROM `$table`");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$res[$row['Key_name']]['name'] = $row['Key_name'];
|
||||
$res[$row['Key_name']]['unique'] = !$row['Non_unique'];
|
||||
$res[$row['Key_name']]['primary'] = $row['Key_name'] === 'PRIMARY';
|
||||
$res[$row['Key_name']]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
|
||||
}
|
||||
$this->free();
|
||||
return array_values($res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,289 +1,504 @@
|
||||
<?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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for MySQL database via improved extension.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'host' - the MySQL server host name
|
||||
* - 'port' - the port number to attempt to connect to the MySQL server
|
||||
* - 'socket' - the socket or named pipe
|
||||
* - 'username' (or 'user')
|
||||
* - 'password' (or 'pass')
|
||||
* - 'persistent' - try to find a persistent link?
|
||||
* - 'database' - the database name to select
|
||||
* - 'charset' - character encoding to set
|
||||
* - 'unbuffered' - sends query without fetching and buffering the result rows automatically?
|
||||
* - 'options' - driver specific constants (MYSQLI_*)
|
||||
* - 'sqlmode' - see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiMySqliDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var mysqli Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var mysqli_result Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
/** @var bool Is buffered (seekable and countable)? */
|
||||
private $buffered;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('mysqli')) {
|
||||
throw new DibiDriverException("PHP extension 'mysqli' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
DibiConnection::alias($config, 'username', 'user');
|
||||
DibiConnection::alias($config, 'password', 'pass');
|
||||
DibiConnection::alias($config, 'host', 'hostname');
|
||||
DibiConnection::alias($config, 'options');
|
||||
DibiConnection::alias($config, 'database');
|
||||
|
||||
// default values
|
||||
if (!isset($config['username'])) $config['username'] = ini_get('mysqli.default_user');
|
||||
if (!isset($config['password'])) $config['password'] = ini_get('mysqli.default_pw');
|
||||
if (!isset($config['socket'])) $config['socket'] = ini_get('mysqli.default_socket');
|
||||
if (!isset($config['port'])) $config['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;
|
||||
}
|
||||
}
|
||||
|
||||
$this->connection = mysqli_init();
|
||||
@mysqli_real_connect($this->connection, $config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $config['socket'], $config['options']); // intentionally @
|
||||
|
||||
if ($errno = mysqli_connect_errno()) {
|
||||
throw new DibiDriverException(mysqli_connect_error(), $errno);
|
||||
}
|
||||
|
||||
if (isset($config['charset'])) {
|
||||
$ok = FALSE;
|
||||
if (version_compare(PHP_VERSION , '5.1.5', '>=')) {
|
||||
// affects the character set used by mysql_real_escape_string() (was added in MySQL 5.0.7 and PHP 5.0.5, fixed in PHP 5.1.5)
|
||||
$ok = @mysqli_set_charset($this->connection, $config['charset']); // intentionally @
|
||||
}
|
||||
if (!$ok) {
|
||||
$ok = @mysqli_query($this->connection, "SET NAMES '$config[charset]'"); // intentionally @
|
||||
if (!$ok) {
|
||||
throw new DibiDriverException(mysqli_error($this->connection), mysqli_errno($this->connection));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['sqlmode'])) {
|
||||
if (!@mysqli_query($this->connection, "SET sql_mode='$config[sqlmode]'")) { // intentionally @
|
||||
throw new DibiDriverException(mysqli_error($this->connection), mysqli_errno($this->connection));
|
||||
}
|
||||
}
|
||||
|
||||
$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 IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
$this->resultSet = @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);
|
||||
}
|
||||
|
||||
return is_object($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
return 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 insertId($sequence)
|
||||
{
|
||||
return mysqli_insert_id($this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->query('START TRANSACTION');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->query('COMMIT');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->query('ROLLBACK');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mysqli
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
case dibi::FIELD_BINARY:
|
||||
return "'" . mysqli_real_escape_string($this->connection, $value) . "'";
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
$value = str_replace('`', '``', $value);
|
||||
return '`' . str_replace('.', '`.`', $value) . '`';
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? 1 : 0;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("'Y-m-d'", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("'Y-m-d H:i:s'", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
if ($limit < 0 && $offset < 1) return;
|
||||
|
||||
// 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**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
if (!$this->buffered) {
|
||||
throw new DibiDriverException('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
|
||||
* @internal
|
||||
*/
|
||||
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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function seek($row)
|
||||
{
|
||||
if (!$this->buffered) {
|
||||
throw new DibiDriverException('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 getColumnsMeta()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$count = mysqli_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$row = (array) mysqli_fetch_field_direct($this->resultSet, $i);
|
||||
$res[] = array(
|
||||
'name' => $row['name'],
|
||||
'table' => $row['orgtable'],
|
||||
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
|
||||
'nativetype' => $types[$row['type']],
|
||||
'vendor' => $row,
|
||||
);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mysqli_result
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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()
|
||||
");*/
|
||||
$this->query("SHOW FULL TABLES");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(FALSE)) {
|
||||
$res[] = array(
|
||||
'name' => $row[0],
|
||||
'view' => isset($row[1]) && $row[1] === 'VIEW',
|
||||
);
|
||||
}
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
/*$table = $this->escape($table, dibi::FIELD_TEXT);
|
||||
$this->query("
|
||||
SELECT *
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
|
||||
");*/
|
||||
$this->query("SHOW COLUMNS FROM `$table`");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$type = explode('(', $row['Type']);
|
||||
$res[] = array(
|
||||
'name' => $row['Field'],
|
||||
'table' => $table,
|
||||
'nativetype' => strtoupper($type[0]),
|
||||
'size' => isset($type[1]) ? (int) $type[1] : NULL,
|
||||
'nullable' => $row['Null'] === 'YES',
|
||||
'default' => $row['Default'],
|
||||
'autoincrement' => $row['Extra'] === 'auto_increment',
|
||||
);
|
||||
}
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
/*$table = $this->escape($table, dibi::FIELD_TEXT);
|
||||
$this->query("
|
||||
SELECT *
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
|
||||
AND REFERENCED_COLUMN_NAME IS NULL
|
||||
");*/
|
||||
$this->query("SHOW INDEX FROM `$table`");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$res[$row['Key_name']]['name'] = $row['Key_name'];
|
||||
$res[$row['Key_name']]['unique'] = !$row['Non_unique'];
|
||||
$res[$row['Key_name']]['primary'] = $row['Key_name'] === 'PRIMARY';
|
||||
$res[$row['Key_name']]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
|
||||
}
|
||||
$this->free();
|
||||
return array_values($res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,278 +1,441 @@
|
||||
<?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
|
||||
|
||||
|
||||
?>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver interacting with databases via ODBC connections.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'dsn' - driver specific DSN
|
||||
* - 'username' (or 'user')
|
||||
* - 'password' (or 'pass')
|
||||
* - 'persistent' - try to find a persistent link?
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiOdbcDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var resource Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var resource Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
/** @var int Cursor */
|
||||
private $row = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('odbc')) {
|
||||
throw new DibiDriverException("PHP extension 'odbc' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
DibiConnection::alias($config, 'username', 'user');
|
||||
DibiConnection::alias($config, 'password', 'pass');
|
||||
|
||||
// default values
|
||||
if (!isset($config['username'])) $config['username'] = ini_get('odbc.default_user');
|
||||
if (!isset($config['password'])) $config['password'] = ini_get('odbc.default_pw');
|
||||
if (!isset($config['dsn'])) $config['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 IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
$this->resultSet = @odbc_exec($this->connection, $sql); // intentionally @
|
||||
|
||||
if ($this->resultSet === FALSE) {
|
||||
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection), 0, $sql);
|
||||
}
|
||||
|
||||
return is_resource($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
return odbc_num_rows($this->resultSet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 insertId($sequence)
|
||||
{
|
||||
throw new NotSupportedException('ODBC does not support autoincrementing.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
if (!odbc_autocommit($this->connection, FALSE)) {
|
||||
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
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.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if (!odbc_rollback($this->connection)) {
|
||||
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
|
||||
}
|
||||
odbc_autocommit($this->connection, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
case dibi::FIELD_BINARY:
|
||||
return "'" . str_replace("'", "''", $value) . "'";
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
|
||||
return '[' . str_replace('.', '].[', $value) . ']';
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? -1 : 0;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("#m/d/Y#", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("#m/d/Y H:i:s#", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
// offset suppot is missing...
|
||||
if ($limit >= 0) {
|
||||
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
|
||||
}
|
||||
|
||||
if ($offset) throw new InvalidArgumentException('Offset is not implemented in driver odbc.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
// 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
|
||||
* @internal
|
||||
*/
|
||||
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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
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 getColumnsMeta()
|
||||
{
|
||||
$count = odbc_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
$res[] = 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 $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
$result = odbc_tables($this->connection);
|
||||
$res = array();
|
||||
while ($row = odbc_fetch_array($result)) {
|
||||
if ($row['TABLE_TYPE'] === 'TABLE' || $row['TABLE_TYPE'] === 'VIEW') {
|
||||
$res[] = array(
|
||||
'name' => $row['TABLE_NAME'],
|
||||
'view' => $row['TABLE_TYPE'] === 'VIEW',
|
||||
);
|
||||
}
|
||||
}
|
||||
odbc_free_result($result);
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
$result = odbc_columns($this->connection);
|
||||
$res = array();
|
||||
while ($row = odbc_fetch_array($result)) {
|
||||
if ($row['TABLE_NAME'] === $table) {
|
||||
$res[] = 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($result);
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
||||
|
402
dibi/drivers/oracle.php
Normal file
402
dibi/drivers/oracle.php
Normal file
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for Oracle database.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'database' (or 'db') - 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
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiOracleDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var resource Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var resource Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
/** @var bool */
|
||||
private $autocommit = TRUE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('oci8')) {
|
||||
throw new DibiDriverException("PHP extension 'oci8' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
DibiConnection::alias($config, 'username', 'user');
|
||||
DibiConnection::alias($config, 'password', 'pass');
|
||||
DibiConnection::alias($config, 'database', 'db');
|
||||
DibiConnection::alias($config, 'charset');
|
||||
|
||||
$this->connection = @oci_new_connect($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 IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
|
||||
$this->resultSet = oci_parse($this->connection, $sql);
|
||||
if ($this->resultSet) {
|
||||
oci_execute($this->resultSet, $this->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
|
||||
$err = oci_error($this->resultSet);
|
||||
if ($err) {
|
||||
throw new DibiDriverException($err['message'], $err['code'], $sql);
|
||||
}
|
||||
} else {
|
||||
$err = oci_error($this->connection);
|
||||
throw new DibiDriverException($err['message'], $err['code'], $sql);
|
||||
}
|
||||
|
||||
return is_resource($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 insertId($sequence)
|
||||
{
|
||||
throw new NotSupportedException('Oracle does not support autoincrementing.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->autocommit = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
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.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
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 $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
case dibi::FIELD_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
|
||||
$value = str_replace('"', '""', $value);
|
||||
return '"' . str_replace('.', '"."', $value) . '"';
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? 1 : 0;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("U", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("U", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
if ($limit < 0 && $offset < 1) return;
|
||||
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
return oci_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
|
||||
* @internal
|
||||
*/
|
||||
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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function seek($row)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 getColumnsMeta()
|
||||
{
|
||||
$count = oci_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
$res[] = 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 $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
452
dibi/drivers/pdo.php
Normal file
452
dibi/drivers/pdo.php
Normal file
@@ -0,0 +1,452 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for PDO.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'dsn' - driver specific DSN
|
||||
* - 'username' (or 'user')
|
||||
* - 'password' (or 'pass')
|
||||
* - 'options' - driver specific options array
|
||||
* - 'pdo' - PDO object (optional)
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiPdoDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var PDO Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var PDOStatement Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
/** @var int|FALSE Affected rows */
|
||||
private $affectedRows = FALSE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('pdo')) {
|
||||
throw new DibiDriverException("PHP extension 'pdo' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
DibiConnection::alias($config, 'username', 'user');
|
||||
DibiConnection::alias($config, 'password', 'pass');
|
||||
DibiConnection::alias($config, 'dsn');
|
||||
DibiConnection::alias($config, 'pdo');
|
||||
DibiConnection::alias($config, 'options');
|
||||
|
||||
if ($config['pdo'] instanceof PDO) {
|
||||
$this->connection = $config['pdo'];
|
||||
|
||||
} 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.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects from a database.
|
||||
* @return void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->connection = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query.
|
||||
* @param string SQL statement.
|
||||
* @return IDibiDriver|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));
|
||||
$list = array('UPDATE'=>1, 'DELETE'=>1, 'INSERT'=>1, 'REPLAC'=>1);
|
||||
|
||||
if (isset($list[$cmd])) {
|
||||
$this->resultSet = NULL;
|
||||
$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);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
$this->resultSet = $this->connection->query($sql);
|
||||
$this->affectedRows = FALSE;
|
||||
|
||||
if ($this->resultSet === FALSE) {
|
||||
$err = $this->connection->errorInfo();
|
||||
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1], $sql);
|
||||
}
|
||||
|
||||
return clone $this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
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 insertId($sequence)
|
||||
{
|
||||
return $this->connection->lastInsertId();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
if (!$this->connection->beginTransaction()) {
|
||||
$err = $this->connection->errorInfo();
|
||||
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if (!$this->connection->commit()) {
|
||||
$err = $this->connection->errorInfo();
|
||||
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
return $this->connection->quote($value, PDO::PARAM_STR);
|
||||
|
||||
case dibi::FIELD_BINARY:
|
||||
return $this->connection->quote($value, PDO::PARAM_LOB);
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
switch ($this->connection->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
||||
case 'mysql':
|
||||
$value = str_replace('`', '``', $value);
|
||||
return '`' . str_replace('.', '`.`', $value) . '`';
|
||||
|
||||
case 'pgsql':
|
||||
$a = strrpos($value, '.');
|
||||
if ($a === FALSE) {
|
||||
return '"' . str_replace('"', '""', $value) . '"';
|
||||
} else {
|
||||
return substr($value, 0, $a) . '."' . str_replace('"', '""', substr($value, $a + 1)) . '"';
|
||||
}
|
||||
|
||||
case 'sqlite':
|
||||
case 'sqlite2':
|
||||
$value = strtr($value, '[]', ' ');
|
||||
case 'odbc':
|
||||
case 'oci': // TODO: not tested
|
||||
case 'mssql':
|
||||
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
|
||||
return '[' . str_replace('.', '].[', $value) . ']';
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $this->connection->quote($value, PDO::PARAM_BOOL);
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("'Y-m-d'", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("'Y-m-d H:i:s'", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
throw new NotSupportedException('PDO does not support applying limit or offset.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
throw new DibiDriverException('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
|
||||
* @internal
|
||||
*/
|
||||
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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function seek($row)
|
||||
{
|
||||
throw new DibiDriverException('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 getColumnsMeta()
|
||||
{
|
||||
$count = $this->resultSet->columnCount();
|
||||
$res = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$row = @$this->resultSet->getColumnMeta($i); // intentionally @
|
||||
if ($row === FALSE) {
|
||||
throw new DibiDriverException('Driver does not support meta data.');
|
||||
}
|
||||
$res[] = array(
|
||||
'name' => $row['name'],
|
||||
'table' => $row['table'],
|
||||
'nativetype' => $row['native_type'],
|
||||
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
|
||||
'vendor' => $row,
|
||||
);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return PDOStatement
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
524
dibi/drivers/postgre.php
Normal file
524
dibi/drivers/postgre.php
Normal file
@@ -0,0 +1,524 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for PostgreSQL database.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'host','hostaddr','port','dbname','user','password','connect_timeout','options','sslmode','service' - see PostgreSQL API
|
||||
* - 'string' - or use connection string
|
||||
* - 'persistent' - try to find a persistent link?
|
||||
* - 'charset' - character encoding to set
|
||||
* - 'schema' - the schema search path
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiPostgreDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @var resource Connection resource */
|
||||
private $connection;
|
||||
|
||||
|
||||
/** @var resource Resultset resource */
|
||||
private $resultSet;
|
||||
|
||||
|
||||
/** @var bool Escape method */
|
||||
private $escMethod = FALSE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('pgsql')) {
|
||||
throw new DibiDriverException("PHP extension 'pgsql' is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function connect(array &$config)
|
||||
{
|
||||
if (isset($config['string'])) {
|
||||
$string = $config['string'];
|
||||
} else {
|
||||
$string = '';
|
||||
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']);
|
||||
}
|
||||
|
||||
$this->escMethod = version_compare(PHP_VERSION , '5.2.0', '>=');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects from a database.
|
||||
* @return void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
pg_close($this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query.
|
||||
* @param string SQL statement.
|
||||
* @param bool update affected rows?
|
||||
* @return IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
$this->resultSet = @pg_query($this->connection, $sql); // intentionally @
|
||||
|
||||
if ($this->resultSet === FALSE) {
|
||||
throw new DibiDriverException(pg_last_error($this->connection), 0, $sql);
|
||||
}
|
||||
|
||||
return is_resource($this->resultSet) && pg_num_fields($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
return pg_affected_rows($this->resultSet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 insertId($sequence)
|
||||
{
|
||||
if ($sequence === NULL) {
|
||||
// PostgreSQL 8.1 is needed
|
||||
$has = $this->query("SELECT LASTVAL()");
|
||||
} else {
|
||||
$has = $this->query("SELECT CURRVAL('$sequence')");
|
||||
}
|
||||
|
||||
if (!$has) return FALSE;
|
||||
|
||||
$row = $this->fetch(FALSE);
|
||||
$this->free();
|
||||
return is_array($row) ? $row[0] : FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->query('START TRANSACTION');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->query('COMMIT');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->query('ROLLBACK');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
if ($this->escMethod) {
|
||||
return "'" . pg_escape_string($this->connection, $value) . "'";
|
||||
} else {
|
||||
return "'" . pg_escape_string($value) . "'";
|
||||
}
|
||||
|
||||
case dibi::FIELD_BINARY:
|
||||
if ($this->escMethod) {
|
||||
return "'" . pg_escape_bytea($this->connection, $value) . "'";
|
||||
} else {
|
||||
return "'" . pg_escape_bytea($value) . "'";
|
||||
}
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
// @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
|
||||
$a = strrpos($value, '.');
|
||||
if ($a === FALSE) {
|
||||
return '"' . str_replace('"', '""', $value) . '"';
|
||||
} else {
|
||||
// table.col delimite as table."col"
|
||||
return substr($value, 0, $a) . '."' . str_replace('"', '""', substr($value, $a + 1)) . '"';
|
||||
}
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? 'TRUE' : 'FALSE';
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date("'Y-m-d'", $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date("'Y-m-d H:i:s'", $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_BINARY:
|
||||
return pg_unescape_bytea($value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
if ($limit >= 0)
|
||||
$sql .= ' LIMIT ' . (int) $limit;
|
||||
|
||||
if ($offset > 0)
|
||||
$sql .= ' OFFSET ' . (int) $offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
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
|
||||
* @internal
|
||||
*/
|
||||
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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
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 getColumnsMeta()
|
||||
{
|
||||
$hasTable = version_compare(PHP_VERSION , '5.2.0', '>=');
|
||||
$count = pg_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$row = array(
|
||||
'name' => pg_field_name($this->resultSet, $i),
|
||||
'table' => $hasTable ? pg_field_table($this->resultSet, $i) : NULL,
|
||||
'nativetype'=> pg_field_type($this->resultSet, $i),
|
||||
);
|
||||
$row['fullname'] = $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'];
|
||||
$res[] = $row;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
$version = pg_version($this->connection);
|
||||
if ($version['server'] < 8) {
|
||||
throw new NotSupportedException('Reflection requires PostgreSQL 8.');
|
||||
}
|
||||
|
||||
$this->query("
|
||||
SELECT table_name as name, CAST(table_type = 'VIEW' AS INTEGER) as view
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = current_schema()
|
||||
");
|
||||
$res = pg_fetch_all($this->resultSet);
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
$_table = $this->escape($table, dibi::FIELD_TEXT);
|
||||
$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.relname = $_table
|
||||
");
|
||||
$primary = (int) pg_fetch_object($this->resultSet)->indkey;
|
||||
|
||||
$this->query("
|
||||
SELECT *
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = $_table AND table_schema = current_schema()
|
||||
ORDER BY ordinal_position
|
||||
");
|
||||
$res = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$size = (int) max($row['character_maximum_length'], $row['numeric_precision']);
|
||||
$res[] = array(
|
||||
'name' => $row['column_name'],
|
||||
'table' => $table,
|
||||
'nativetype' => strtoupper($row['udt_name']),
|
||||
'size' => $size ? $size : NULL,
|
||||
'nullable' => $row['is_nullable'] === 'YES',
|
||||
'default' => $row['column_default'],
|
||||
'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval',
|
||||
'vendor' => $row,
|
||||
);
|
||||
}
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
$_table = $this->escape($table, dibi::FIELD_TEXT);
|
||||
$this->query("
|
||||
SELECT ordinal_position, column_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = $_table AND table_schema = current_schema()
|
||||
ORDER BY ordinal_position
|
||||
");
|
||||
|
||||
$columns = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$columns[$row['ordinal_position']] = $row['column_name'];
|
||||
}
|
||||
|
||||
$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.relname = $_table
|
||||
");
|
||||
|
||||
$res = array();
|
||||
while ($row = $this->fetch(TRUE)) {
|
||||
$res[$row['relname']]['name'] = $row['relname'];
|
||||
$res[$row['relname']]['unique'] = $row['indisunique'] === 't';
|
||||
$res[$row['relname']]['primary'] = $row['indisprimary'] === 't';
|
||||
foreach (explode(' ', $row['indkey']) as $index) {
|
||||
$res[$row['relname']]['columns'][] = $columns[$index];
|
||||
}
|
||||
}
|
||||
$this->free();
|
||||
return array_values($res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
@@ -1,241 +1,422 @@
|
||||
<?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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The dibi driver for SQLite database.
|
||||
*
|
||||
* Connection options:
|
||||
* - 'database' (or 'file') - the filename of the SQLite database
|
||||
* - 'persistent' - try to find a persistent link?
|
||||
* - 'unbuffered' - sends query without fetching and buffering the result rows automatically?
|
||||
* - 'lazy' - if TRUE, connection will be established only when required
|
||||
* - 'formatDate' - how to format date in SQL (@see date)
|
||||
* - 'formatDateTime' - how to format datetime in SQL (@see date)
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiSqliteDriver extends DibiObject implements IDibiDriver
|
||||
{
|
||||
|
||||
/** @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;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('sqlite')) {
|
||||
throw new DibiDriverException("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 (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']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects from a database.
|
||||
* @return void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
sqlite_close($this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query.
|
||||
* @param string SQL statement.
|
||||
* @return IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
DibiDriverException::tryError();
|
||||
if ($this->buffered) {
|
||||
$this->resultSet = sqlite_query($this->connection, $sql);
|
||||
} else {
|
||||
$this->resultSet = sqlite_unbuffered_query($this->connection, $sql);
|
||||
}
|
||||
if (DibiDriverException::catchError($msg)) {
|
||||
throw new DibiDriverException($msg, sqlite_last_error($this->connection), $sql);
|
||||
}
|
||||
|
||||
return is_resource($this->resultSet) ? clone $this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 affectedRows()
|
||||
{
|
||||
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 insertId($sequence)
|
||||
{
|
||||
return sqlite_last_insert_rowid($this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->query('BEGIN');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->query('COMMIT');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
$this->query('ROLLBACK');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function escape($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
case dibi::FIELD_BINARY:
|
||||
return "'" . sqlite_escape_string($value) . "'";
|
||||
|
||||
case dibi::IDENTIFIER:
|
||||
return '[' . str_replace('.', '].[', strtr($value, '[]', ' ')) . ']';
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return $value ? 1 : 0;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
return date($this->fmtDate, $value);
|
||||
|
||||
case dibi::FIELD_DATETIME:
|
||||
return date($this->fmtDateTime, $value);
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function unescape($value, $type)
|
||||
{
|
||||
throw new InvalidArgumentException('Unsupported type.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
if ($limit < 0 && $offset < 1) return;
|
||||
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
public function rowCount()
|
||||
{
|
||||
if (!$this->buffered) {
|
||||
throw new DibiDriverException('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
|
||||
* @internal
|
||||
*/
|
||||
public function fetch($assoc)
|
||||
{
|
||||
$row = sqlite_fetch_array($this->resultSet, $assoc ? SQLITE_ASSOC : SQLITE_NUM);
|
||||
if ($assoc && $row) {
|
||||
$tmp = array();
|
||||
foreach ($row as $k => $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 boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function seek($row)
|
||||
{
|
||||
if (!$this->buffered) {
|
||||
throw new DibiDriverException('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 getColumnsMeta()
|
||||
{
|
||||
$count = sqlite_num_fields($this->resultSet);
|
||||
$res = array();
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$name = str_replace(array('[', ']'), '', sqlite_field_name($this->resultSet, $i));
|
||||
$pair = explode('.', $name);
|
||||
$res[] = array(
|
||||
'name' => isset($pair[1]) ? $pair[1] : $pair[0],
|
||||
'table' => isset($pair[1]) ? $pair[0] : NULL,
|
||||
'fullname' => $name,
|
||||
'nativetype' => NULL,
|
||||
);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResultResource()
|
||||
{
|
||||
return $this->resultSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
$this->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
|
||||
");
|
||||
$res = sqlite_fetch_all($this->resultSet, SQLITE_ASSOC);
|
||||
$this->free();
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
||||
|
601
dibi/libs/DibiConnection.php
Normal file
601
dibi/libs/DibiConnection.php
Normal file
@@ -0,0 +1,601 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi connection.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiConnection extends DibiObject
|
||||
{
|
||||
/** @var array Current connection configuration */
|
||||
private $config;
|
||||
|
||||
/** @var IDibiDriver Driver */
|
||||
private $driver;
|
||||
|
||||
/** @var IDibiProfiler Profiler */
|
||||
private $profiler;
|
||||
|
||||
/** @var bool Is connected? */
|
||||
private $connected = FALSE;
|
||||
|
||||
/** @var bool Is in transaction? */
|
||||
private $inTxn = FALSE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates object and (optionally) connects to a database.
|
||||
* @param array|string|ArrayObject connection parameters
|
||||
* @param string connection name
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function __construct($config, $name = NULL)
|
||||
{
|
||||
if (class_exists(/*Nette::*/'Debug', FALSE)) {
|
||||
/*Nette::*/Debug::addColophon(array('dibi', 'getColophon'));
|
||||
}
|
||||
|
||||
// DSN string
|
||||
if (is_string($config)) {
|
||||
parse_str($config, $config);
|
||||
|
||||
} elseif ($config instanceof ArrayObject) {
|
||||
$config = (array) $config;
|
||||
|
||||
} elseif (!is_array($config)) {
|
||||
throw new InvalidArgumentException('Configuration must be array, string or ArrayObject.');
|
||||
}
|
||||
|
||||
if (!isset($config['driver'])) {
|
||||
$config['driver'] = dibi::$defaultDriver;
|
||||
}
|
||||
|
||||
$driver = preg_replace('#[^a-z0-9_]#', '_', $config['driver']);
|
||||
$class = "Dibi" . $driver . "Driver";
|
||||
if (!class_exists($class, FALSE)) {
|
||||
include_once dirname(__FILE__) . "/../drivers/$driver.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;
|
||||
|
||||
if (!empty($config['profiler'])) {
|
||||
$class = $config['profiler'];
|
||||
if (is_numeric($class) || is_bool($class)) {
|
||||
$class = 'DibiProfiler';
|
||||
}
|
||||
if (!class_exists($class)) {
|
||||
throw new DibiException("Unable to create instance of dibi profiler '$class'.");
|
||||
}
|
||||
$this->setProfiler(new $class);
|
||||
}
|
||||
|
||||
if (empty($config['lazy'])) {
|
||||
$this->connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Automatically frees the resources allocated for this result set.
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// disconnects and rolls back transaction - do not rely on auto-disconnect and rollback!
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
* @return void
|
||||
*/
|
||||
final protected function connect()
|
||||
{
|
||||
if (!$this->connected) {
|
||||
if ($this->profiler !== NULL) {
|
||||
$ticket = $this->profiler->before($this, IDibiProfiler::CONNECT);
|
||||
}
|
||||
$this->driver->connect($this->config);
|
||||
$this->connected = TRUE;
|
||||
if (isset($ticket)) {
|
||||
$this->profiler->after($ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnects from a database.
|
||||
* @return void
|
||||
*/
|
||||
final public function disconnect()
|
||||
{
|
||||
if ($this->connected) {
|
||||
if ($this->inTxn) {
|
||||
$this->rollback();
|
||||
}
|
||||
$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=NULL)
|
||||
{
|
||||
if (isset($config[$key])) return;
|
||||
|
||||
if ($alias !== NULL && isset($config[$alias])) {
|
||||
$config[$key] = $config[$alias];
|
||||
unset($config[$alias]);
|
||||
} else {
|
||||
$config[$key] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return resource
|
||||
*/
|
||||
final public function getResource()
|
||||
{
|
||||
return $this->driver->getResource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates (translates) and executes SQL query.
|
||||
* @param array|mixed one or more arguments
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function query($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->connect();
|
||||
$trans = new DibiTranslator($this->driver);
|
||||
if ($trans->translate($args)) {
|
||||
return $this->nativeQuery($trans->sql);
|
||||
} else {
|
||||
throw new DibiException('SQL translate error: ' . $trans->sql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and prints SQL query.
|
||||
* @param array|mixed one or more arguments
|
||||
* @return bool
|
||||
*/
|
||||
final public function test($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->connect();
|
||||
$trans = new DibiTranslator($this->driver);
|
||||
$ok = $trans->translate($args);
|
||||
dibi::dump($trans->sql);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the SQL query.
|
||||
* @param string SQL statement.
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function nativeQuery($sql)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if ($this->profiler !== NULL) {
|
||||
$event = IDibiProfiler::QUERY;
|
||||
if (preg_match('#\s*(SELECT|UPDATE|INSERT|DELETE)#i', $sql, $matches)) {
|
||||
static $events = array(
|
||||
'SELECT' => IDibiProfiler::SELECT, 'UPDATE' => IDibiProfiler::UPDATE,
|
||||
'INSERT' => IDibiProfiler::INSERT, 'DELETE' => IDibiProfiler::DELETE,
|
||||
);
|
||||
$event = $events[strtoupper($matches[1])];
|
||||
}
|
||||
$ticket = $this->profiler->before($this, $event, $sql);
|
||||
}
|
||||
// TODO: move to profiler?
|
||||
dibi::$numOfQueries++;
|
||||
dibi::$sql = $sql;
|
||||
dibi::$elapsedTime = FALSE;
|
||||
$time = -microtime(TRUE);
|
||||
|
||||
if ($res = $this->driver->query($sql)) { // intentionally =
|
||||
$res = new DibiResult($res, $this->config);
|
||||
}
|
||||
|
||||
$time += microtime(TRUE);
|
||||
dibi::$elapsedTime = $time;
|
||||
dibi::$totalTime += $time;
|
||||
|
||||
if (isset($ticket)) {
|
||||
$this->profiler->after($ticket, $res);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
|
||||
* @return int number of rows
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
$rows = $this->driver->affectedRows();
|
||||
if (!is_int($rows) || $rows < 0) throw new DibiException('Cannot retrieve number of affected rows.');
|
||||
return $rows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||
* @param string optional sequence name
|
||||
* @return int
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function insertId($sequence = NULL)
|
||||
{
|
||||
$id = $this->driver->insertId($sequence);
|
||||
if ($id < 1) throw new DibiException('Cannot retrieve last generated ID.');
|
||||
return (int) $id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
*/
|
||||
public function begin()
|
||||
{
|
||||
$this->connect();
|
||||
if ($this->inTxn) {
|
||||
throw new DibiException('There is already an active transaction.');
|
||||
}
|
||||
if ($this->profiler !== NULL) {
|
||||
$ticket = $this->profiler->before($this, IDibiProfiler::BEGIN);
|
||||
}
|
||||
$this->driver->begin();
|
||||
$this->inTxn = TRUE;
|
||||
if (isset($ticket)) {
|
||||
$this->profiler->after($ticket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if (!$this->inTxn) {
|
||||
throw new DibiException('There is no active transaction.');
|
||||
}
|
||||
if ($this->profiler !== NULL) {
|
||||
$ticket = $this->profiler->before($this, IDibiProfiler::COMMIT);
|
||||
}
|
||||
$this->driver->commit();
|
||||
$this->inTxn = FALSE;
|
||||
if (isset($ticket)) {
|
||||
$this->profiler->after($ticket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if (!$this->inTxn) {
|
||||
throw new DibiException('There is no active transaction.');
|
||||
}
|
||||
if ($this->profiler !== NULL) {
|
||||
$ticket = $this->profiler->before($this, IDibiProfiler::ROLLBACK);
|
||||
}
|
||||
$this->driver->rollback();
|
||||
$this->inTxn = FALSE;
|
||||
if (isset($ticket)) {
|
||||
$this->profiler->after($ticket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string unescaped string
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string escaped and quoted string
|
||||
*/
|
||||
public function escape($value, $type = dibi::FIELD_TEXT)
|
||||
{
|
||||
$this->connect(); // MySQL & PDO require connection
|
||||
return $this->driver->escape($value, $type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
*/
|
||||
public function unescape($value, $type = dibi::FIELD_BINARY)
|
||||
{
|
||||
return $this->driver->unescape($value, $type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Delimites identifier (table's or column's name, etc.).
|
||||
* @param string identifier
|
||||
* @return string delimited identifier
|
||||
*/
|
||||
public function delimite($value)
|
||||
{
|
||||
return $this->driver->escape($value, dibi::IDENTIFIER);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function applyLimit(&$sql, $limit, $offset)
|
||||
{
|
||||
$this->driver->applyLimit($sql, $limit, $offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* 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, array $args)
|
||||
{
|
||||
return $this->command()->update('%n', $table)->set($args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string table
|
||||
* @param array
|
||||
* @return DibiFluent
|
||||
*/
|
||||
public function insert($table, array $args)
|
||||
{
|
||||
return $this->command()->insert()
|
||||
->into('%n', $table, '(%n)', array_keys($args))->values('%l', array_values($args));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string table
|
||||
* @return DibiFluent
|
||||
*/
|
||||
public function delete($table)
|
||||
{
|
||||
return $this->command()->delete()->from('%n', $table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* profiler ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param IDibiProfiler
|
||||
* @return void
|
||||
*/
|
||||
public function setProfiler(IDibiProfiler $profiler = NULL)
|
||||
{
|
||||
$this->profiler = $profiler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return IDibiProfiler
|
||||
*/
|
||||
public function getProfiler()
|
||||
{
|
||||
return $this->profiler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* misc ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Import SQL dump from file - extreme fast!
|
||||
* @param string filename
|
||||
* @return int count of sql commands
|
||||
*/
|
||||
public function loadFile($file)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
@set_time_limit(0); // intentionally @
|
||||
|
||||
$handle = @fopen($file, 'r'); // intentionally @
|
||||
if (!$handle) {
|
||||
throw new FileNotFoundException("Cannot open file '$file'.");
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$sql = '';
|
||||
while (!feof($handle)) {
|
||||
$s = fgets($handle);
|
||||
$sql .= $s;
|
||||
if (substr(rtrim($s), -1) === ';') {
|
||||
$this->driver->query($sql);
|
||||
$sql = '';
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a information about the current database.
|
||||
* @return DibiDatabaseInfo
|
||||
*/
|
||||
public function getDatabaseInfo()
|
||||
{
|
||||
return new DibiDatabaseInfo($this->driver, isset($this->config['database']) ? $this->config['database'] : NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prevents unserialization.
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prevents serialization.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
|
||||
}
|
||||
|
||||
}
|
92
dibi/libs/DibiDataSource.php
Normal file
92
dibi/libs/DibiDataSource.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of IDataSource for dibi.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiDataSource extends DibiObject implements IDataSource
|
||||
{
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
/** @var int */
|
||||
private $count;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string SQL command or table name, as data source
|
||||
* @param DibiConnection connection
|
||||
*/
|
||||
public function __construct($sql, DibiConnection $connection = NULL)
|
||||
{
|
||||
if (strpos($sql, ' ') === FALSE) {
|
||||
// table name
|
||||
$this->sql = $sql;
|
||||
} else {
|
||||
// SQL command
|
||||
$this->sql = '(' . $sql . ') AS [source]';
|
||||
}
|
||||
|
||||
$this->connection = $connection === NULL ? dibi::getConnection() : $connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param int offset
|
||||
* @param int limit
|
||||
* @param array columns
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
public function getIterator($offset = NULL, $limit = NULL)
|
||||
{
|
||||
return $this->connection->query('
|
||||
SELECT *
|
||||
FROM', $this->sql, '
|
||||
%ofs %lmt', $offset, $limit
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
if ($this->count === NULL) {
|
||||
$this->count = $this->connection->query('
|
||||
SELECT COUNT(*) FROM', $this->sql
|
||||
)->fetchSingle();
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
}
|
612
dibi/libs/DibiDatabaseInfo.php
Normal file
612
dibi/libs/DibiDatabaseInfo.php
Normal file
@@ -0,0 +1,612 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reflection metadata class for a database.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiDatabaseInfo extends DibiObject
|
||||
{
|
||||
/** @var IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var array */
|
||||
private $tables;
|
||||
|
||||
|
||||
|
||||
public function __construct(IDibiDriver $driver, $name)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return array of DibiTableInfo
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
$this->init();
|
||||
return array_values($this->tables);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return array of 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->driver->getTables() as $info) {
|
||||
$this->tables[strtolower($info['name'])] = new DibiTableInfo($this->driver, $info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reflection metadata class for a database table.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiTableInfo extends DibiObject
|
||||
{
|
||||
/** @var IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @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(IDibiDriver $driver, array $info)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
$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 array of DibiColumnInfo
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
$this->initColumns();
|
||||
return array_values($this->columns);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return array of 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 array of DibiForeignKeyInfo
|
||||
*/
|
||||
public function getForeignKeys()
|
||||
{
|
||||
$this->initForeignKeys();
|
||||
return $this->foreignKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return array of 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->driver->getColumns($this->name) as $info) {
|
||||
$this->columns[strtolower($info['name'])] = new DibiColumnInfo($this->driver, $info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function initIndexes()
|
||||
{
|
||||
if ($this->indexes === NULL) {
|
||||
$this->initColumns();
|
||||
$this->indexes = array();
|
||||
foreach ($this->driver->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 NotImplementedException;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reflection metadata class for a table column.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiColumnInfo extends DibiObject
|
||||
{
|
||||
/** @var array */
|
||||
private static $types;
|
||||
|
||||
/** @var IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @var array (name, nativetype, [table], [fullname], [size], [nullable], [default], [autoincrement], [vendor]) */
|
||||
private $info;
|
||||
|
||||
/** @var string */
|
||||
private $type;
|
||||
|
||||
|
||||
|
||||
public function __construct(IDibiDriver $driver, array $info)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
$this->info = $info;
|
||||
$this->type = self::detectType($this->info['nativetype']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->info['name'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTable()
|
||||
{
|
||||
return !empty($this->info['table']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return DibiTableInfo
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
if (empty($this->info['table'])) {
|
||||
throw new DibiException("Table name is unknown.");
|
||||
}
|
||||
return new DibiTableInfo($this->driver, array('name' => $this->info['table']));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @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 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
|
||||
*/
|
||||
public static function detectType($type)
|
||||
{
|
||||
static $patterns = array(
|
||||
'BYTE|COUNTER|SERIAL|INT|LONG' => dibi::FIELD_INTEGER,
|
||||
'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC' => dibi::FIELD_FLOAT,
|
||||
'^TIME$' => dibi::FIELD_TIME,
|
||||
'TIME' => dibi::FIELD_DATETIME, // DATETIME, TIMESTAMP
|
||||
'YEAR|DATE' => dibi::FIELD_DATE,
|
||||
'BYTEA|BLOB|BIN' => dibi::FIELD_BINARY,
|
||||
'BOOL|BIT' => dibi::FIELD_BOOL,
|
||||
);
|
||||
|
||||
if (!isset(self::$types[$type])) {
|
||||
self::$types[$type] = dibi::FIELD_TEXT;
|
||||
foreach ($patterns as $s => $val) {
|
||||
if (preg_match("#$s#i", $type)) {
|
||||
return self::$types[$type] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$types[$type];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reflection metadata class for a foreign key.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
* @todo
|
||||
*/
|
||||
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
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
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']);
|
||||
}
|
||||
|
||||
}
|
156
dibi/libs/DibiException.php
Normal file
156
dibi/libs/DibiException.php
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi common exception.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* database server exception.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiDriverException extends DibiException implements /*Nette::*/IDebuggable
|
||||
{
|
||||
/** @var string */
|
||||
private static $errorMsg;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
|
||||
/**
|
||||
* Construct an dibi driver exception.
|
||||
* @param string Message describing the exception
|
||||
* @param int Some code
|
||||
* @param string SQL command
|
||||
*/
|
||||
public function __construct($message = NULL, $code = 0, $sql = NULL)
|
||||
{
|
||||
parent::__construct($message, (int) $code);
|
||||
$this->sql = $sql;
|
||||
// TODO: add $profiler->exception($this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string The SQL passed to the constructor
|
||||
*/
|
||||
final public function getSql()
|
||||
{
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string string represenation of exception with SQL command
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return parent::__toString() . ($this->sql ? "\nSQL: " . $this->sql : '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* interface Nette::IDebuggable ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Returns custom panels.
|
||||
* @return array
|
||||
*/
|
||||
public function getPanels()
|
||||
{
|
||||
$panels = array();
|
||||
if ($this->sql !== NULL) {
|
||||
$panels['SQL'] = array(
|
||||
'expanded' => TRUE,
|
||||
'content' => dibi::dump($this->sql, TRUE),
|
||||
);
|
||||
}
|
||||
return $panels;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* error catching ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starts catching potential errors/warnings
|
||||
* @return void
|
||||
*/
|
||||
public static function tryError()
|
||||
{
|
||||
set_error_handler(array(__CLASS__, '_errorHandler'), E_ALL);
|
||||
self::$errorMsg = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns catched error/warning message.
|
||||
* @param string catched message
|
||||
* @return bool
|
||||
*/
|
||||
public static function catchError(& $message)
|
||||
{
|
||||
restore_error_handler();
|
||||
$message = self::$errorMsg;
|
||||
self::$errorMsg = NULL;
|
||||
return $message !== NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal error handler. Do not call directly.
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
405
dibi/libs/DibiFluent.php
Normal file
405
dibi/libs/DibiFluent.php
Normal file
@@ -0,0 +1,405 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi SQL builder via fluent interfaces. EXPERIMENTAL!
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiFluent extends DibiObject
|
||||
{
|
||||
/** @var array */
|
||||
public static $masks = array(
|
||||
'SELECT' => array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'GROUP BY',
|
||||
'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET', '%end'),
|
||||
'UPDATE' => array('UPDATE', 'SET', 'WHERE', 'ORDER BY', 'LIMIT', '%end'),
|
||||
'INSERT' => array('INSERT', 'INTO', 'VALUES', 'SELECT', '%end'),
|
||||
'DELETE' => array('DELETE', 'FROM', 'USING', 'WHERE', 'ORDER BY', 'LIMIT', '%end'),
|
||||
);
|
||||
|
||||
/** @var array */
|
||||
public static $modifiers = array(
|
||||
'SELECT' => '%n',
|
||||
'IN' => '%l',
|
||||
'VALUES' => '%l',
|
||||
'SET' => '%a',
|
||||
'WHERE' => '%and',
|
||||
'HAVING' => '%and',
|
||||
'ORDER BY' => '%by',
|
||||
'GROUP BY' => '%by',
|
||||
);
|
||||
|
||||
/** @var array */
|
||||
public static $separators = array(
|
||||
'SELECT' => ',',
|
||||
'FROM' => FALSE,
|
||||
'WHERE' => 'AND',
|
||||
'GROUP BY' => ',',
|
||||
'HAVING' => 'AND',
|
||||
'ORDER BY' => ',',
|
||||
'LIMIT' => FALSE,
|
||||
'OFFSET' => FALSE,
|
||||
'SET' => ',',
|
||||
'VALUES' => ',',
|
||||
'INTO' => FALSE,
|
||||
);
|
||||
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string */
|
||||
private $command;
|
||||
|
||||
/** @var array */
|
||||
private $clauses = array();
|
||||
|
||||
/** @var array */
|
||||
private $flags = array();
|
||||
|
||||
/** @var array */
|
||||
private $cursor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param DibiConnection
|
||||
*/
|
||||
public function __construct(DibiConnection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends new argument to the clause.
|
||||
* @param string clause name
|
||||
* @param array arguments
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function __call($clause, $args)
|
||||
{
|
||||
$clause = self::_formatClause($clause);
|
||||
|
||||
// lazy initialization
|
||||
if ($this->command === NULL) {
|
||||
if (isset(self::$masks[$clause])) {
|
||||
$this->clauses = array_fill_keys(self::$masks[$clause], NULL);
|
||||
}
|
||||
$this->cursor = & $this->clauses[$clause];
|
||||
$this->cursor = array();
|
||||
$this->command = $clause;
|
||||
}
|
||||
|
||||
// special types or argument
|
||||
if (count($args) === 1) {
|
||||
$arg = $args[0];
|
||||
// TODO: really ignore TRUE?
|
||||
if ($arg === TRUE) { // flag
|
||||
$args = array();
|
||||
|
||||
} elseif (is_string($arg) && preg_match('#^[a-z][a-z0-9_.]*$#i', $arg)) { // identifier
|
||||
$args = array('%n', $arg);
|
||||
|
||||
} elseif (is_array($arg)) { // any array
|
||||
if (isset(self::$modifiers[$clause])) {
|
||||
$args = array(self::$modifiers[$clause], $arg);
|
||||
|
||||
} elseif (is_string(key($arg))) { // associative array
|
||||
$args = array('%a', $arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($clause, $this->clauses)) {
|
||||
// append to clause
|
||||
$this->cursor = & $this->clauses[$clause];
|
||||
|
||||
// TODO: really delete?
|
||||
if ($args === array(FALSE)) {
|
||||
$this->cursor = NULL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (isset(self::$separators[$clause])) {
|
||||
$sep = self::$separators[$clause];
|
||||
if ($sep === FALSE) {
|
||||
$this->cursor = array();
|
||||
|
||||
} elseif (!empty($this->cursor)) {
|
||||
$this->cursor[] = $sep;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// append to currect flow
|
||||
if ($args === array(FALSE)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->cursor[] = $clause;
|
||||
}
|
||||
|
||||
if ($this->cursor === NULL) {
|
||||
$this->cursor = array();
|
||||
}
|
||||
|
||||
array_splice($this->cursor, count($this->cursor), 0, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switch to a clause.
|
||||
* @param string clause name
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function clause($clause, $remove = FALSE)
|
||||
{
|
||||
$this->cursor = & $this->clauses[self::_formatClause($clause)];
|
||||
|
||||
if ($remove) {
|
||||
$this->cursor = NULL;
|
||||
|
||||
} elseif ($this->cursor === NULL) {
|
||||
$this->cursor = array();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change a SQL flag.
|
||||
* @param string flag name
|
||||
* @param bool value
|
||||
* @return DibiFluent provides a fluent interface
|
||||
*/
|
||||
public function setFlag($flag, $value = TRUE)
|
||||
{
|
||||
$flag = strtoupper($flag);
|
||||
if ($value) {
|
||||
$this->flags[$flag] = TRUE;
|
||||
} else {
|
||||
unset($this->flags[$flag]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is a flag set?
|
||||
* @param string flag name
|
||||
* @return bool
|
||||
*/
|
||||
final public function getFlag($flag)
|
||||
{
|
||||
return isset($this->flags[strtoupper($flag)]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns SQL command.
|
||||
* @return string
|
||||
*/
|
||||
final public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and executes SQL query.
|
||||
* @return DibiResult|NULL result set object (if any)
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
return $this->connection->query($this->_export());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates, executes SQL query and fetches the single row.
|
||||
* @return DibiRow|FALSE array on success, FALSE if no next record
|
||||
* @throws DibiException
|
||||
*/
|
||||
public function fetch()
|
||||
{
|
||||
if ($this->command === 'SELECT') {
|
||||
$this->clauses['LIMIT'] = array(1);
|
||||
}
|
||||
return $this->execute()->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'] = array(1);
|
||||
}
|
||||
return $this->execute()->fetchSingle();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all records from table.
|
||||
* @param int offset
|
||||
* @param int limit
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAll($offset = NULL, $limit = NULL)
|
||||
{
|
||||
return $this->execute()->fetchAll($offset, $limit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all records from table and returns associative tree.
|
||||
* Associative descriptor: assoc1,#,assoc2,=,assoc3,@
|
||||
* builds a tree: $data[assoc1][index][assoc2]['assoc3']->value = {record}
|
||||
* @param string associative descriptor
|
||||
* @return array
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function fetchAssoc($assoc)
|
||||
{
|
||||
return $this->execute()->fetchAssoc($assoc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all records from table like $key => $value pairs.
|
||||
* @param string associative key
|
||||
* @param string value
|
||||
* @return array
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function fetchPairs($key = NULL, $value = NULL)
|
||||
{
|
||||
return $this->execute()->fetchPairs($key, $value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates and prints SQL query or it's part.
|
||||
* @param string clause name
|
||||
* @return bool
|
||||
*/
|
||||
public function test($clause = NULL)
|
||||
{
|
||||
return $this->connection->test($this->_export($clause));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates parameters for DibiTranslator.
|
||||
* @param string clause name
|
||||
* @return array
|
||||
*/
|
||||
protected function _export($clause = NULL)
|
||||
{
|
||||
if ($clause === NULL) {
|
||||
$data = $this->clauses;
|
||||
|
||||
} else {
|
||||
$clause = self::_formatClause($clause);
|
||||
if (array_key_exists($clause, $this->clauses)) {
|
||||
$data = array($clause => $this->clauses[$clause]);
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
$args = array();
|
||||
foreach ($data as $clause => $statement) {
|
||||
if ($statement !== NULL) {
|
||||
if ($clause[0] !== '%') {
|
||||
$args[] = $clause;
|
||||
if ($clause === $this->command) {
|
||||
$args[] = implode(' ', array_keys($this->flags));
|
||||
}
|
||||
}
|
||||
array_splice($args, count($args), 0, $statement);
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Format camelCase clause name to UPPER CASE.
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
private static function _formatClause($s)
|
||||
{
|
||||
if ($s === 'order' || $s === 'group') {
|
||||
$s .= 'By';
|
||||
trigger_error("Did you mean '$s'?", E_USER_NOTICE);
|
||||
}
|
||||
return strtoupper(preg_replace('#[A-Z]#', ' $0', $s));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns (highlighted) SQL query.
|
||||
* @return string
|
||||
*/
|
||||
final public function __toString()
|
||||
{
|
||||
ob_start();
|
||||
$this->test();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// PHP < 5.2 compatibility
|
||||
if (!function_exists('array_fill_keys')) {
|
||||
function array_fill_keys($keys, $value)
|
||||
{
|
||||
return array_combine($keys, array_fill(0, count($keys), $value));
|
||||
}
|
||||
}
|
335
dibi/libs/DibiObject.php
Normal file
335
dibi/libs/DibiObject.php
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DibiObject is the ultimate ancestor of all instantiable classes.
|
||||
*
|
||||
* DibiObject is copy of Nette::Object from Nette Framework (http://nettephp.com).
|
||||
*
|
||||
* 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
|
||||
* @copyright Copyright (c) 2005, 2008 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 ::MemberAccessException
|
||||
*/
|
||||
public function __call($name, $args)
|
||||
{
|
||||
$class = get_class($this);
|
||||
|
||||
if ($name === '') {
|
||||
throw new /*::*/MemberAccessException("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 /*::*/MemberAccessException("Call to undefined method $class::$name().");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Call to undefined static method.
|
||||
* @param string method name (in lower case!)
|
||||
* @param array arguments
|
||||
* @return mixed
|
||||
* @throws ::MemberAccessException
|
||||
*/
|
||||
public static function __callStatic($name, $args)
|
||||
{
|
||||
$class = get_called_class();
|
||||
throw new /*::*/MemberAccessException("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 ::MemberAccessException if the property is not defined.
|
||||
*/
|
||||
public function &__get($name)
|
||||
{
|
||||
$class = get_class($this);
|
||||
|
||||
if ($name === '') {
|
||||
throw new /*::*/MemberAccessException("Cannot read an class '$class' property without name.");
|
||||
}
|
||||
|
||||
// property getter support
|
||||
$name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character
|
||||
$m = 'get' . $name;
|
||||
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' . $name;
|
||||
if (self::hasAccessor($class, $m)) {
|
||||
$val = $this->$m();
|
||||
return $val;
|
||||
}
|
||||
|
||||
$name = func_get_arg(0);
|
||||
throw new /*::*/MemberAccessException("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 ::MemberAccessException if the property is not defined or is read-only
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$class = get_class($this);
|
||||
|
||||
if ($name === '') {
|
||||
throw new /*::*/MemberAccessException("Cannot assign to an class '$class' property without name.");
|
||||
}
|
||||
|
||||
// property setter support
|
||||
$name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character
|
||||
if (self::hasAccessor($class, 'get' . $name) || self::hasAccessor($class, 'is' . $name)) {
|
||||
$m = 'set' . $name;
|
||||
if (self::hasAccessor($class, $m)) {
|
||||
$this->$m($value);
|
||||
return;
|
||||
|
||||
} else {
|
||||
$name = func_get_arg(0);
|
||||
throw new /*::*/MemberAccessException("Cannot assign to a read-only property $class::\$$name.");
|
||||
}
|
||||
}
|
||||
|
||||
$name = func_get_arg(0);
|
||||
throw new /*::*/MemberAccessException("Cannot assign to an undeclared property $class::\$$name.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is property defined?
|
||||
* @param string property name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
$name[0] = $name[0] & "\xDF";
|
||||
return $name !== '' && self::hasAccessor(get_class($this), 'get' . $name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Access to undeclared property.
|
||||
* @param string property name
|
||||
* @return void
|
||||
* @throws ::MemberAccessException
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
$class = get_class($this);
|
||||
throw new /*::*/MemberAccessException("Cannot unset an 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]);
|
||||
}
|
||||
|
||||
}
|
229
dibi/libs/DibiProfiler.php
Normal file
229
dibi/libs/DibiProfiler.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi basic logger & profiler (experimental).
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiProfiler extends DibiObject implements IDibiProfiler
|
||||
{
|
||||
/** @var string Name of the file where SQL errors should be logged */
|
||||
private $file;
|
||||
|
||||
/** @var bool log to firebug? */
|
||||
private $useFirebug;
|
||||
|
||||
/** @var int */
|
||||
private $filter = self::ALL;
|
||||
|
||||
/** @var array */
|
||||
public $tickets = array();
|
||||
|
||||
/** @var array */
|
||||
public static $table = array(array('Time', 'SQL Statement', 'Rows', 'Connection'));
|
||||
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->useFirebug = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string filename
|
||||
* @return void
|
||||
*/
|
||||
public function setFile($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param int
|
||||
* @return void
|
||||
*/
|
||||
public function setFilter($filter)
|
||||
{
|
||||
$this->filter = (int) $filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Before event notification.
|
||||
* @param DibiConnection
|
||||
* @param int event name
|
||||
* @param string sql
|
||||
* @return int
|
||||
*/
|
||||
public function before(DibiConnection $connection, $event, $sql = NULL)
|
||||
{
|
||||
$this->tickets[] = array($connection, $event, $sql);
|
||||
end($this->tickets);
|
||||
return key($this->tickets);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* After event notification.
|
||||
* @param int
|
||||
* @param DibiResult
|
||||
* @return void
|
||||
*/
|
||||
public function after($ticket, $res = NULL)
|
||||
{
|
||||
if (!isset($this->tickets[$ticket])) {
|
||||
throw new InvalidArgumentException('Bad ticket number.');
|
||||
}
|
||||
|
||||
list($connection, $event, $sql) = $this->tickets[$ticket];
|
||||
|
||||
if (($event & $this->filter) === 0) return;
|
||||
|
||||
if ($event & self::QUERY) {
|
||||
if ($this->useFirebug) {
|
||||
self::$table[] = array(
|
||||
sprintf('%0.3f', dibi::$elapsedTime * 1000),
|
||||
trim($sql),
|
||||
$res instanceof DibiResult ? count($res) : '-',
|
||||
$connection->getConfig('driver') . '/' . $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 = array(
|
||||
array(
|
||||
'Type' => 'TABLE',
|
||||
'Label' => 'dibi profiler (' . dibi::$numOfQueries . ' SQL queries took ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms)',
|
||||
),
|
||||
self::$table,
|
||||
);
|
||||
$payload = function_exists('json_encode') ? json_encode($payload) : self::json_encode($payload);
|
||||
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|");
|
||||
header("X-Wf-dibi-Index: d$num");
|
||||
}
|
||||
|
||||
if ($this->file) {
|
||||
$this->writeFile(
|
||||
"OK: " . $sql
|
||||
. ($res instanceof DibiResult ? ";\n-- rows: " . count($res) : '')
|
||||
. "\n-- takes: " . sprintf('%0.3f', dibi::$elapsedTime * 1000) . ' ms'
|
||||
. "\n-- driver: " . $connection->getConfig('driver') . '/' . $connection->getConfig('name')
|
||||
. "\n-- " . date('Y-m-d H:i:s')
|
||||
. "\n\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* After exception notification.
|
||||
* @param DibiDriverException
|
||||
* @return void
|
||||
*/
|
||||
public function exception(DibiDriverException $exception)
|
||||
{
|
||||
if ((self::EXCEPTION & $this->filter) === 0) return;
|
||||
|
||||
if ($this->useFirebug) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
if ($this->file) {
|
||||
$message = $exception->getMessage();
|
||||
$code = $exception->getCode();
|
||||
if ($code) {
|
||||
$message = "[$code] $message";
|
||||
}
|
||||
$this->writeFile(
|
||||
"ERROR: $message"
|
||||
. "\n-- SQL: " . dibi::$sql
|
||||
. "\n-- driver: " //. $connection->getConfig('driver')
|
||||
. ";\n-- " . date('Y-m-d H:i:s')
|
||||
. "\n\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function writeFile($message)
|
||||
{
|
||||
$handle = fopen($this->file, 'a');
|
||||
if (!$handle) return; // or throw exception?
|
||||
flock($handle, LOCK_EX);
|
||||
fwrite($handle, $message);
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function json_encode($val)
|
||||
{
|
||||
// indexed array
|
||||
if (is_array($val) && (!$val
|
||||
|| array_keys($val) === range(0, count($val) - 1))) {
|
||||
return '[' . implode(',', array_map(array(__CLASS__, 'json_encode'), $val)) . ']';
|
||||
}
|
||||
|
||||
// associative array
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$tmp = array();
|
||||
foreach ($val as $k => $v) {
|
||||
$tmp[] = self::json_encode((string) $k) . ':' . self::json_encode($v);
|
||||
}
|
||||
return '{' . implode(',', $tmp) . '}';
|
||||
}
|
||||
|
||||
if (is_string($val)) {
|
||||
$val = str_replace(array("\\", "\x00"), array("\\\\", "\\u0000"), $val); // due to bug #40915
|
||||
return '"' . addcslashes($val, "\x8\x9\xA\xC\xD/\"") . '"';
|
||||
}
|
||||
|
||||
if (is_int($val) || is_float($val)) {
|
||||
return rtrim(rtrim(number_format($val, 5, '.', ''), '0'), '.');
|
||||
}
|
||||
|
||||
if (is_bool($val)) {
|
||||
return $val ? 'true' : 'false';
|
||||
}
|
||||
|
||||
return 'null';
|
||||
}
|
||||
|
||||
}
|
629
dibi/libs/DibiResult.php
Normal file
629
dibi/libs/DibiResult.php
Normal file
@@ -0,0 +1,629 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi 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
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiResult extends DibiObject implements IDataSource
|
||||
{
|
||||
/** @var array IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @var array Translate table */
|
||||
private $xlat;
|
||||
|
||||
/** @var array Cache for $driver->getColumnsMeta() */
|
||||
private $meta;
|
||||
|
||||
/** @var bool Already fetched? Used for allowance for first seek(0) */
|
||||
private $fetched = FALSE;
|
||||
|
||||
/** @var array|FALSE Qualifiy each column name with the table name? */
|
||||
private $withTables = FALSE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param IDibiDriver
|
||||
* @param array
|
||||
*/
|
||||
public function __construct($driver, $config)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
|
||||
if (!empty($config[dibi::RESULT_WITH_TABLES])) {
|
||||
$this->setWithTables(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Automatically frees the resources allocated for this result set.
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
@$this->free(); // intentionally @
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
final public function getResource()
|
||||
{
|
||||
return $this->getDriver()->getResultResource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
final public function seek($row)
|
||||
{
|
||||
return ($row !== 0 || $this->fetched) ? (bool) $this->getDriver()->seek($row) : TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
final public function rowCount()
|
||||
{
|
||||
return $this->getDriver()->rowCount();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Frees the resources allocated for this result set.
|
||||
* @return void
|
||||
*/
|
||||
final public function free()
|
||||
{
|
||||
if ($this->driver !== NULL) {
|
||||
$this->driver->free();
|
||||
$this->driver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Qualifiy each column name with the table name?
|
||||
* @param bool
|
||||
* @return void
|
||||
* @throws DibiException
|
||||
*/
|
||||
final public function setWithTables($val)
|
||||
{
|
||||
if ($val) {
|
||||
$cols = array();
|
||||
foreach ($this->getMeta() as $info) {
|
||||
$name = $info['fullname'];
|
||||
if (isset($cols[$name])) {
|
||||
$fix = 1;
|
||||
while (isset($cols[$name . '#' . $fix])) $fix++;
|
||||
$name .= '#' . $fix;
|
||||
}
|
||||
$cols[$name] = TRUE;
|
||||
}
|
||||
$this->withTables = array_keys($cols);
|
||||
|
||||
} else {
|
||||
$this->withTables = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Qualifiy each key with the table name?
|
||||
* @return bool
|
||||
*/
|
||||
final public function getWithTables()
|
||||
{
|
||||
return (bool) $this->withTables;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
if ($this->withTables === FALSE) {
|
||||
$row = $this->getDriver()->fetch(TRUE);
|
||||
if (!is_array($row)) return FALSE;
|
||||
|
||||
} else {
|
||||
$row = $this->getDriver()->fetch(FALSE);
|
||||
if (!is_array($row)) return FALSE;
|
||||
$row = array_combine($this->withTables, $row);
|
||||
}
|
||||
|
||||
$this->fetched = TRUE;
|
||||
|
||||
// types-converting?
|
||||
if ($this->xlat !== NULL) {
|
||||
foreach ($this->xlat as $col => $type) {
|
||||
if (isset($row[$col])) {
|
||||
$row[$col] = $this->convert($row[$col], $type['type'], $type['format']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DibiRow($row, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Like fetch(), but returns only first field.
|
||||
* @return mixed value on success, FALSE if no next record
|
||||
*/
|
||||
final public function fetchSingle()
|
||||
{
|
||||
$row = $this->getDriver()->fetch(TRUE);
|
||||
if (!is_array($row)) return FALSE;
|
||||
$this->fetched = TRUE;
|
||||
$value = reset($row);
|
||||
|
||||
// types-converting?
|
||||
$key = key($row);
|
||||
if (isset($this->xlat[$key])) {
|
||||
$type = $this->xlat[$key];
|
||||
return $this->convert($value, $type['type'], $type['format']);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all records from table.
|
||||
* @param int offset
|
||||
* @param int limit
|
||||
* @return array of 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.
|
||||
* Associative descriptor: assoc1,#,assoc2,=,assoc3,@
|
||||
* builds a tree: $data[assoc1][index][assoc2]['assoc3']->value = {record}
|
||||
* @param string associative descriptor
|
||||
* @return DibiRow
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
final public function fetchAssoc($assoc)
|
||||
{
|
||||
$this->seek(0);
|
||||
$row = $this->fetch();
|
||||
if (!$row) return array(); // empty result set
|
||||
|
||||
$data = NULL;
|
||||
$assoc = explode(',', $assoc);
|
||||
|
||||
// check columns
|
||||
foreach ($assoc as $as) {
|
||||
// offsetExists ignores NULL in PHP 5.2.1, isset() surprisingly NULL accepts
|
||||
if ($as !== '#' && $as !== '=' && $as !== '@' && !isset($row[$as])) {
|
||||
throw new InvalidArgumentException("Unknown column '$as' in associative descriptor.");
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// make associative tree
|
||||
do {
|
||||
$arr = (array) $row;
|
||||
$x = & $data;
|
||||
|
||||
// iterative deepening
|
||||
foreach ($assoc as $i => $as) {
|
||||
if ($as === '#') { // indexed-array node
|
||||
$x = & $x[];
|
||||
|
||||
} elseif ($as === '=') { // "record" node
|
||||
if ($x === NULL) {
|
||||
$x = $arr;
|
||||
$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[ $arr[ $as ] ];
|
||||
}
|
||||
}
|
||||
|
||||
if ($x === NULL) { // build leaf
|
||||
if ($leaf === '=') {
|
||||
$x = $arr;
|
||||
} 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((array) $row);
|
||||
$key = $tmp[0];
|
||||
if (count($row) < 2) { // indexed-array
|
||||
do {
|
||||
$data[] = $row[$key];
|
||||
} while ($row = $this->fetch());
|
||||
return $data;
|
||||
}
|
||||
|
||||
$value = $tmp[1];
|
||||
|
||||
} else {
|
||||
if (!isset($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 (!isset($row[$key])) {
|
||||
throw new InvalidArgumentException("Unknown key column '$key'.");
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
$data[ $row[$key] ] = $row[$value];
|
||||
} while ($row = $this->fetch());
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Define column type.
|
||||
* @param string column
|
||||
* @param string type (use constant Dibi::FIELD_*)
|
||||
* @param string optional format
|
||||
* @return void
|
||||
*/
|
||||
final public function setType($col, $type, $format = NULL)
|
||||
{
|
||||
$this->xlat[$col] = array('type' => $type, 'format' => $format);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Autodetect column types.
|
||||
* @return void
|
||||
*/
|
||||
final public function detectTypes()
|
||||
{
|
||||
foreach ($this->getMeta() as $info) {
|
||||
$this->xlat[$info['name']] = array('type' => $info['type'], 'format' => NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Define multiple columns types.
|
||||
* @param array
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
final public function setTypes(array $types)
|
||||
{
|
||||
$this->xlat = $types;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns column type.
|
||||
* @return array ($type, $format)
|
||||
*/
|
||||
final public function getType($col)
|
||||
{
|
||||
return isset($this->xlat[$col]) ? $this->xlat[$col] : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts value to specified type and format
|
||||
* @return array ($type, $format)
|
||||
*/
|
||||
final public function convert($value, $type, $format = NULL)
|
||||
{
|
||||
if ($value === NULL || $value === FALSE) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case dibi::FIELD_TEXT:
|
||||
return (string) $value;
|
||||
|
||||
case dibi::FIELD_BINARY:
|
||||
return $this->getDriver()->unescape($value, $type);
|
||||
|
||||
case dibi::FIELD_INTEGER:
|
||||
return (int) $value;
|
||||
|
||||
case dibi::FIELD_FLOAT:
|
||||
return (float) $value;
|
||||
|
||||
case dibi::FIELD_DATE:
|
||||
case dibi::FIELD_DATETIME:
|
||||
$value = strtotime($value);
|
||||
return $format === NULL ? $value : date($format, $value);
|
||||
|
||||
case dibi::FIELD_BOOL:
|
||||
return ((bool) $value) && $value !== 'f' && $value !== 'F';
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets an array of meta informations about columns.
|
||||
* @return array of DibiColumnInfo
|
||||
*/
|
||||
final public function getColumns()
|
||||
{
|
||||
$cols = array();
|
||||
foreach ($this->getMeta() as $info) {
|
||||
$cols[] = new DibiColumnInfo($this->driver, $info);
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param bool
|
||||
* @return array of string
|
||||
*/
|
||||
public function getColumnNames($withTables = FALSE)
|
||||
{
|
||||
$cols = array();
|
||||
foreach ($this->getMeta() as $info) {
|
||||
$cols[] = $info[$withTables ? 'fullname' : 'name'];
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Displays complete result-set as HTML table for debug purposes.
|
||||
* @return void
|
||||
*/
|
||||
final public function dump()
|
||||
{
|
||||
$i = 0;
|
||||
$this->seek(0);
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Required by the IteratorAggregate interface.
|
||||
* @param int offset
|
||||
* @param int limit
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
final public function getIterator($offset = NULL, $limit = NULL)
|
||||
{
|
||||
return new ArrayIterator($this->fetchAll($offset, $limit));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Required by the Countable interface.
|
||||
* @return int
|
||||
*/
|
||||
final public function count()
|
||||
{
|
||||
return $this->rowCount();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Safe access to property $driver.
|
||||
* @return IDibiDriver
|
||||
* @throws InvalidStateException
|
||||
*/
|
||||
private function getDriver()
|
||||
{
|
||||
if ($this->driver === NULL) {
|
||||
throw new InvalidStateException('Resultset was released from memory.');
|
||||
}
|
||||
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Meta lazy initialization.
|
||||
* @return array
|
||||
*/
|
||||
private function getMeta()
|
||||
{
|
||||
if ($this->meta === NULL) {
|
||||
$this->meta = $this->getDriver()->getColumnsMeta();
|
||||
foreach ($this->meta as & $row) {
|
||||
$row['type'] = DibiColumnInfo::detectType($row['nativetype']);
|
||||
}
|
||||
}
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi result-set row
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiRow extends ArrayObject
|
||||
{
|
||||
}
|
420
dibi/libs/DibiTableX.php
Normal file
420
dibi/libs/DibiTableX.php
Normal file
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Experimental object-oriented interface to database tables.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
abstract class DibiTableX extends DibiObject
|
||||
{
|
||||
/** @var string primary key mask */
|
||||
public static $primaryMask = 'id';
|
||||
|
||||
/** @var bool */
|
||||
public static $lowerCase = TRUE;
|
||||
|
||||
/** @var DibiConnection */
|
||||
private $connection;
|
||||
|
||||
/** @var string table name */
|
||||
protected $name;
|
||||
|
||||
/** @var string primary key name */
|
||||
protected $primary;
|
||||
|
||||
/** @var string primary key type */
|
||||
protected $primaryModifier = '%i';
|
||||
|
||||
/** @var bool primary key is auto increment */
|
||||
protected $primaryAutoIncrement = TRUE;
|
||||
|
||||
/** @var array */
|
||||
protected $blankRow = array();
|
||||
|
||||
/** @var mixed; TRUE means autodetect, or array of pairs [type, format] */
|
||||
protected $types = array();
|
||||
|
||||
|
||||
/**
|
||||
* Table constructor.
|
||||
* @param DibiConnection
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(DibiConnection $connection = NULL)
|
||||
{
|
||||
$this->connection = $connection === NULL ? dibi::getConnection() : $connection;
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the table name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the primary key name.
|
||||
* @return string
|
||||
*/
|
||||
public function getPrimary()
|
||||
{
|
||||
return $this->primary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the dibi connection.
|
||||
* @return DibiConnection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup object.
|
||||
* @return void
|
||||
*/
|
||||
protected function setup()
|
||||
{
|
||||
// autodetect table name
|
||||
if ($this->name === NULL) {
|
||||
$name = $this->getClass();
|
||||
if (FALSE !== ($pos = strrpos($name, ':'))) {
|
||||
$name = substr($name, $pos + 1);
|
||||
}
|
||||
if (self::$lowerCase) {
|
||||
$name = strtolower($name);
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
// autodetect primary key name
|
||||
if ($this->primary === NULL) {
|
||||
$this->primary = str_replace(
|
||||
array('%p', '%s'),
|
||||
array($this->name, trim($this->name, 's')), // the simplest inflector in the world :-))
|
||||
self::$primaryMask
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* basic commands ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Inserts row into a table.
|
||||
* @param array|object
|
||||
* @return int new primary key
|
||||
*/
|
||||
public function insert($data)
|
||||
{
|
||||
$this->connection->query(
|
||||
'INSERT INTO %n', $this->name, '%v', $this->prepare($data)
|
||||
);
|
||||
|
||||
return $this->primaryAutoIncrement ? $this->connection->insertId() : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates rows in a table.
|
||||
* @param mixed primary key value(s)
|
||||
* @param array|object
|
||||
* @return int number of updated rows
|
||||
*/
|
||||
public function update($where, $data)
|
||||
{
|
||||
$data = $this->prepare($data);
|
||||
if ($where === NULL && isset($data[$this->primary])) {;
|
||||
$where = $data[$this->primary];
|
||||
unset($data[$this->primary]);
|
||||
}
|
||||
|
||||
$this->connection->query(
|
||||
'UPDATE %n', $this->name,
|
||||
'SET %a', $data,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
return $this->connection->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Inserts or updates rows in a table.
|
||||
* @param array|object
|
||||
* @return int (new) primary key
|
||||
*/
|
||||
public function insertOrUpdate($data)
|
||||
{
|
||||
$data = $this->prepare($data);
|
||||
if (!isset($data[$this->primary])) {
|
||||
throw new InvalidArgumentException("Missing primary key '$this->primary' in dataset.");
|
||||
}
|
||||
|
||||
try {
|
||||
$this->connection->query(
|
||||
'INSERT INTO %n', $this->name, '%v', $data
|
||||
);
|
||||
|
||||
} catch (DibiDriverException $e) {
|
||||
$where = $data[$this->primary];
|
||||
unset($data[$this->primary]);
|
||||
$this->connection->query(
|
||||
'UPDATE %n', $this->name,
|
||||
'SET %a', $data,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Deletes rows from a table by primary key.
|
||||
* @param mixed primary key value(s)
|
||||
* @return int number of deleted rows
|
||||
*/
|
||||
public function delete($where)
|
||||
{
|
||||
$this->connection->query(
|
||||
'DELETE FROM %n', $this->name,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
|
||||
);
|
||||
return $this->connection->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Finds rows by primary key.
|
||||
* @param mixed primary key value(s)
|
||||
* @return DibiResult
|
||||
*/
|
||||
public function find($what)
|
||||
{
|
||||
if (!is_array($what)) {
|
||||
$what = func_get_args();
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $what, ')'
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Selects all rows.
|
||||
* @param array conditions
|
||||
* @param string|array column to order by
|
||||
* @return DibiResult
|
||||
*/
|
||||
public function findAll($conditions = NULL, $order = NULL)
|
||||
{
|
||||
if (!is_array($order)) {
|
||||
$order = func_get_args();
|
||||
if (is_array($conditions)) {
|
||||
array_shift($order);
|
||||
} else {
|
||||
$conditions = NULL;
|
||||
}
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'%ex', $conditions ? array('WHERE %and', $conditions) : NULL,
|
||||
'%ex', $order ? array('ORDER BY %by', $order) : NULL
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches single row.
|
||||
* @param scalar|array primary key value
|
||||
* @return DibiRow
|
||||
*/
|
||||
public function fetch($conditions)
|
||||
{
|
||||
if (is_array($conditions)) {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %and', $conditions
|
||||
))->fetch();
|
||||
}
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %n=' . $this->primaryModifier, $this->primary, $conditions
|
||||
))->fetch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a blank row (not fetched from database).
|
||||
* @return DibiRow
|
||||
*/
|
||||
public function createBlank()
|
||||
{
|
||||
$row = new DibiRow($this->blankRow, 2);
|
||||
$row[$this->primary] = NULL;
|
||||
return $row;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* User data pre-processing.
|
||||
* @param array|object
|
||||
* @return array
|
||||
*/
|
||||
protected function prepare($data)
|
||||
{
|
||||
if (is_object($data)) {
|
||||
return (array) $data;
|
||||
|
||||
} elseif (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Dataset must be array or anonymous object.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* User DibiResult post-processing.
|
||||
* @param DibiResult
|
||||
* @return DibiResult
|
||||
*/
|
||||
protected function complete($res)
|
||||
{
|
||||
if (is_array($this->types)) {
|
||||
$res->setTypes($this->types);
|
||||
|
||||
} elseif ($this->types === TRUE) {
|
||||
$res->detectTypes();
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* fluent SQL builders ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates fluent SQL builder.
|
||||
* @return DibiFluent
|
||||
*/
|
||||
public function command()
|
||||
{
|
||||
return new DibiFluent($this->connection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string column name
|
||||
* @return DibiFluent
|
||||
*/
|
||||
public function select($args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
return $this->command()->__call('select', $args)->from($this->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************* magic fetching ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Magic fetch.
|
||||
* - $row = $model->fetchByUrl('about-us');
|
||||
* - $arr = $model->fetchAllByCategoryIdAndVisibility(5, TRUE);
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @return DibiRow|array
|
||||
*/
|
||||
public function __call($name, $args)
|
||||
{
|
||||
if (strncmp($name, 'fetchBy', 7) === 0) { // single row
|
||||
$single = TRUE;
|
||||
$name = substr($name, 7);
|
||||
|
||||
} elseif (strncmp($name, 'fetchAllBy', 10) === 0) { // multi row
|
||||
$name = substr($name, 10);
|
||||
|
||||
} else {
|
||||
parent::__call($name, $args);
|
||||
}
|
||||
|
||||
// ProductIdAndTitle -> array('product', 'title')
|
||||
$parts = explode('_and_', strtolower(preg_replace('#(.)(?=[A-Z])#', '$1_', $name)));
|
||||
|
||||
if (count($parts) !== count($args)) {
|
||||
throw new InvalidArgumentException("Magic fetch expects " . count($parts) . " parameters, but " . count($args) . " was given.");
|
||||
}
|
||||
|
||||
if (isset($single)) {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %and', array_combine($parts, $args),
|
||||
'LIMIT 1'
|
||||
))->fetch();
|
||||
} else {
|
||||
return $this->complete($this->connection->query(
|
||||
'SELECT * FROM %n', $this->name,
|
||||
'WHERE %and', array_combine($parts, $args)
|
||||
))->fetchAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
abstract class DibiTable extends DibiTableX
|
||||
{
|
||||
}
|
479
dibi/libs/DibiTranslator.php
Normal file
479
dibi/libs/DibiTranslator.php
Normal file
@@ -0,0 +1,479 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi SQL translator.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @package dibi
|
||||
*/
|
||||
final class DibiTranslator extends DibiObject
|
||||
{
|
||||
/** @var string */
|
||||
public $sql;
|
||||
|
||||
/** @var IDibiDriver */
|
||||
private $driver;
|
||||
|
||||
/** @var int */
|
||||
private $cursor;
|
||||
|
||||
/** @var array */
|
||||
private $args;
|
||||
|
||||
/** @var bool */
|
||||
private $hasError;
|
||||
|
||||
/** @var bool */
|
||||
private $comment;
|
||||
|
||||
/** @var int */
|
||||
private $ifLevel;
|
||||
|
||||
/** @var int */
|
||||
private $ifLevelStart;
|
||||
|
||||
/** @var int */
|
||||
private $limit;
|
||||
|
||||
/** @var int */
|
||||
private $offset;
|
||||
|
||||
|
||||
|
||||
public function __construct(IDibiDriver $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* return IDibiDriver.
|
||||
*/
|
||||
public function getDriver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates SQL.
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
public function translate(array $args)
|
||||
{
|
||||
$this->limit = -1;
|
||||
$this->offset = 0;
|
||||
$this->hasError = FALSE;
|
||||
$commandIns = NULL;
|
||||
$lastArr = NULL;
|
||||
// shortcuts
|
||||
$cursor = & $this->cursor;
|
||||
$cursor = 0;
|
||||
$this->args = array_values($args);
|
||||
$args = & $this->args;
|
||||
|
||||
// conditional sql
|
||||
$this->ifLevel = $this->ifLevelStart = 0;
|
||||
$comment = & $this->comment;
|
||||
$comment = FALSE;
|
||||
|
||||
// iterate
|
||||
$sql = array();
|
||||
while ($cursor < count($args))
|
||||
{
|
||||
$arg = $args[$cursor];
|
||||
$cursor++;
|
||||
|
||||
// simple string means SQL
|
||||
if (is_string($arg)) {
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($arg, '`[\'"%');
|
||||
|
||||
if (strlen($arg) === $toSkip) { // needn't be translated
|
||||
$sql[] = $arg;
|
||||
} else {
|
||||
$sql[] = substr($arg, 0, $toSkip)
|
||||
/*
|
||||
preg_replace_callback('/
|
||||
(?=`|\[|\'|"|%) ## speed-up
|
||||
(?:
|
||||
`(.+?)`| ## 1) `identifier`
|
||||
\[(.+?)\]| ## 2) [identifier]
|
||||
(\')((?:\'\'|[^\'])*)\'| ## 3,4) string
|
||||
(")((?:""|[^"])*)"| ## 5,6) "string"
|
||||
(\'|") ## 7) lone-quote
|
||||
%([a-zA-Z]{1,4})(?![a-zA-Z])|## 8) modifier
|
||||
)/xs',
|
||||
*/ // note: this can change $this->args & $this->cursor & ...
|
||||
. preg_replace_callback('/(?=`|\[|\'|"|%)(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|%([a-zA-Z]{1,4})(?![a-zA-Z]))/s',
|
||||
array($this, 'cb'),
|
||||
substr($arg, $toSkip)
|
||||
);
|
||||
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comment) {
|
||||
$sql[] = '...';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($arg)) {
|
||||
if (is_string(key($arg))) {
|
||||
// associative array -> autoselect between SET or VALUES & LIST
|
||||
if ($commandIns === NULL) {
|
||||
$commandIns = strtoupper(substr(ltrim($args[0]), 0, 6));
|
||||
$commandIns = $commandIns === 'INSERT' || $commandIns === 'REPLAC';
|
||||
$sql[] = $this->formatValue($arg, $commandIns ? 'v' : 'a');
|
||||
} else {
|
||||
if ($lastArr === $cursor - 1) $sql[] = ',';
|
||||
$sql[] = $this->formatValue($arg, $commandIns ? 'l' : 'a');
|
||||
}
|
||||
$lastArr = $cursor;
|
||||
continue;
|
||||
|
||||
} elseif ($cursor === 1) {
|
||||
// implicit array expansion
|
||||
$cursor = 0;
|
||||
array_splice($args, 0, 1, $arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// default processing
|
||||
$sql[] = $this->formatValue($arg, FALSE);
|
||||
} // while
|
||||
|
||||
|
||||
if ($comment) $sql[] = "*/";
|
||||
|
||||
$sql = implode(' ', $sql);
|
||||
|
||||
// apply limit
|
||||
if ($this->limit > -1 || $this->offset > 0) {
|
||||
$this->driver->applyLimit($sql, $this->limit, $this->offset);
|
||||
}
|
||||
|
||||
$this->sql = $sql;
|
||||
return !$this->hasError;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply modifier to single value.
|
||||
* @param mixed
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function formatValue($value, $modifier)
|
||||
{
|
||||
// array processing (with or without modifier)
|
||||
if (is_array($value) || $value instanceof ArrayObject) {
|
||||
|
||||
$vx = $kx = array();
|
||||
$operator = ', ';
|
||||
switch ($modifier) {
|
||||
case 'and':
|
||||
case 'or': // key=val AND key IS NULL AND ...
|
||||
$operator = ' ' . strtoupper($modifier) . ' ';
|
||||
if (empty($value)) {
|
||||
return '1';
|
||||
|
||||
} elseif (!is_string(key($value))) {
|
||||
foreach ($value as $v) {
|
||||
$vx[] = $this->formatValue($v, 'sql');
|
||||
}
|
||||
|
||||
} else {
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$k = $this->delimite($pair[0]);
|
||||
$v = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
$op = isset($pair[1]) && $pair[1] === 'l' ? 'IN' : ($v === 'NULL' ? 'IS' : '=');
|
||||
$vx[] = $k . ' ' . $op . ' ' . $v;
|
||||
}
|
||||
}
|
||||
return implode($operator, $vx);
|
||||
|
||||
case 'a': // key=val, key=val, ...
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$vx[] = $this->delimite($pair[0]) . '='
|
||||
. $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return implode($operator, $vx);
|
||||
|
||||
|
||||
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] : FALSE);
|
||||
}
|
||||
return '(' . implode(', ', $vx) . ')';
|
||||
|
||||
|
||||
case 'v': // (key, key, ...) VALUES (val, val, ...)
|
||||
foreach ($value as $k => $v) {
|
||||
$pair = explode('%', $k, 2); // split into identifier & modifier
|
||||
$kx[] = $this->delimite($pair[0]);
|
||||
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE);
|
||||
}
|
||||
return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
|
||||
|
||||
case 'by': // key ASC, key DESC
|
||||
foreach ($value as $k => $v) {
|
||||
if (is_string($k)) {
|
||||
$v = (is_string($v) && strncasecmp($v, 'd', 1)) || $v > 0 ? 'ASC' : 'DESC';
|
||||
$vx[] = $this->delimite($k) . ' ' . $v;
|
||||
} else {
|
||||
$vx[] = $this->delimite($v);
|
||||
}
|
||||
}
|
||||
return implode(', ', $vx);
|
||||
|
||||
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) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
if ($value instanceof IDibiVariable) {
|
||||
return $value->toSql($this, $modifier);
|
||||
}
|
||||
|
||||
if (!is_scalar($value)) { // array is already processed
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected type ' . gettype($value) . '**';
|
||||
}
|
||||
|
||||
switch ($modifier) {
|
||||
case 's': // string
|
||||
case 'bin':// binary
|
||||
case 'b': // boolean
|
||||
return $this->driver->escape($value, $modifier);
|
||||
|
||||
case 'sn': // string or NULL
|
||||
return $value == '' ? 'NULL' : $this->driver->escape($value, dibi::FIELD_TEXT); // notice two equal signs
|
||||
|
||||
case 'i': // signed int
|
||||
case 'u': // unsigned int, ignored
|
||||
// support for long numbers - keep them unchanged
|
||||
if (is_string($value) && preg_match('#[+-]?\d+(e\d+)?$#A', $value)) {
|
||||
return $value;
|
||||
}
|
||||
return (string) (int) ($value + 0);
|
||||
|
||||
case 'f': // float
|
||||
// support for 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
|
||||
}
|
||||
return rtrim(rtrim(number_format($value, 5, '.', ''), '0'), '.');
|
||||
|
||||
case 'd': // date
|
||||
case 't': // datetime
|
||||
return $this->driver->escape(is_string($value) ? strtotime($value) : $value, $modifier);
|
||||
|
||||
case 'by':
|
||||
case 'n': // identifier name
|
||||
return $this->delimite($value);
|
||||
|
||||
case 'sql':// preserve as SQL
|
||||
$value = (string) $value;
|
||||
// speed-up - is regexp required?
|
||||
$toSkip = strcspn($value, '`[\'"');
|
||||
if (strlen($value) === $toSkip) { // needn't be translated
|
||||
return $value;
|
||||
} else {
|
||||
return substr($value, 0, $toSkip)
|
||||
. preg_replace_callback('/(?=`|\[|\'|")(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"(\'|"))/s',
|
||||
array($this, 'cb'),
|
||||
substr($value, $toSkip)
|
||||
);
|
||||
}
|
||||
|
||||
case 'and':
|
||||
case 'or':
|
||||
case 'a':
|
||||
case 'l':
|
||||
case 'v':
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected type ' . gettype($value) . '**';
|
||||
|
||||
default:
|
||||
$this->hasError = TRUE;
|
||||
return "**Unknown or invalid modifier %$modifier**";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// without modifier procession
|
||||
if (is_string($value))
|
||||
return $this->driver->escape($value, dibi::FIELD_TEXT);
|
||||
|
||||
if (is_int($value) || is_float($value))
|
||||
return rtrim(rtrim(number_format($value, 5, '.', ''), '0'), '.');
|
||||
|
||||
if (is_bool($value))
|
||||
return $this->driver->escape($value, dibi::FIELD_BOOL);
|
||||
|
||||
if ($value === NULL)
|
||||
return 'NULL';
|
||||
|
||||
if ($value instanceof IDibiVariable)
|
||||
return $value->toSql($this, NULL);
|
||||
|
||||
$this->hasError = TRUE;
|
||||
return '**Unexpected ' . gettype($value) . '**';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* PREG callback from translate() or formatValue().
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
private function cb($matches)
|
||||
{
|
||||
// [1] => `ident`
|
||||
// [2] => [ident]
|
||||
// [3] => '
|
||||
// [4] => string
|
||||
// [5] => "
|
||||
// [6] => string
|
||||
// [7] => lone-quote
|
||||
// [8] => modifier (when called from self::translate())
|
||||
|
||||
if (!empty($matches[8])) { // modifier
|
||||
$mod = $matches[8];
|
||||
$cursor = & $this->cursor;
|
||||
|
||||
if ($cursor >= count($this->args) && $mod !== 'else' && $mod !== 'end') {
|
||||
$this->hasError = TRUE;
|
||||
return "**Extra modifier %$mod**";
|
||||
}
|
||||
|
||||
if ($mod === 'if') {
|
||||
$this->ifLevel++;
|
||||
$cursor++;
|
||||
if (!$this->comment && !$this->args[$cursor - 1]) {
|
||||
// open comment
|
||||
$this->ifLevelStart = $this->ifLevel;
|
||||
$this->comment = TRUE;
|
||||
return "/*";
|
||||
}
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'else') {
|
||||
if ($this->ifLevelStart === $this->ifLevel) {
|
||||
$this->ifLevelStart = 0;
|
||||
$this->comment = FALSE;
|
||||
return "*/";
|
||||
} elseif (!$this->comment) {
|
||||
$this->ifLevelStart = $this->ifLevel;
|
||||
$this->comment = TRUE;
|
||||
return "/*";
|
||||
}
|
||||
|
||||
} elseif ($mod === 'end') {
|
||||
$this->ifLevel--;
|
||||
if ($this->ifLevelStart === $this->ifLevel + 1) {
|
||||
// close comment
|
||||
$this->ifLevelStart = 0;
|
||||
$this->comment = FALSE;
|
||||
return "*/";
|
||||
}
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'ex') { // array expansion
|
||||
array_splice($this->args, $cursor, 1, $this->args[$cursor]);
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'lmt') { // apply limit
|
||||
if ($this->args[$cursor] !== NULL) $this->limit = (int) $this->args[$cursor];
|
||||
$cursor++;
|
||||
return '';
|
||||
|
||||
} elseif ($mod === 'ofs') { // apply offset
|
||||
if ($this->args[$cursor] !== NULL) $this->offset = (int) $this->args[$cursor];
|
||||
$cursor++;
|
||||
return '';
|
||||
|
||||
} else { // default processing
|
||||
$cursor++;
|
||||
return $this->formatValue($this->args[$cursor - 1], $mod);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->comment) return '...';
|
||||
|
||||
if ($matches[1]) // SQL identifiers: `ident`
|
||||
return $this->delimite($matches[1]);
|
||||
|
||||
if ($matches[2]) // SQL identifiers: [ident]
|
||||
return $this->delimite($matches[2]);
|
||||
|
||||
if ($matches[3]) // SQL strings: '...'
|
||||
return $this->driver->escape( str_replace("''", "'", $matches[4]), dibi::FIELD_TEXT);
|
||||
|
||||
if ($matches[5]) // SQL strings: "..."
|
||||
return $this->driver->escape( str_replace('""', '"', $matches[6]), dibi::FIELD_TEXT);
|
||||
|
||||
if ($matches[7]) { // string quote
|
||||
$this->hasError = TRUE;
|
||||
return '**Alone quote**';
|
||||
}
|
||||
|
||||
die('this should be never executed');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply substitutions to indentifier and delimites it.
|
||||
* @param string indentifier
|
||||
* @return string
|
||||
*/
|
||||
private function delimite($value)
|
||||
{
|
||||
return $this->driver->escape(dibi::substitute($value), dibi::IDENTIFIER);
|
||||
}
|
||||
|
||||
|
||||
} // class DibiTranslator
|
49
dibi/libs/DibiVariable.php
Normal file
49
dibi/libs/DibiVariable.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default implemenation of IDibiVariable.
|
||||
* @package dibi
|
||||
*/
|
||||
class DibiVariable extends DibiObject implements IDibiVariable
|
||||
{
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
|
||||
/** @var string */
|
||||
public $modifier;
|
||||
|
||||
|
||||
public function __construct($value, $modifier)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->modifier = $modifier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function toSql(DibiTranslator $translator, $modifier)
|
||||
{
|
||||
return $translator->formatValue($this->value, $this->modifier);
|
||||
}
|
||||
|
||||
}
|
@@ -1,101 +0,0 @@
|
||||
<?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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@@ -1,164 +0,0 @@
|
||||
<?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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
@@ -1,67 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
|
||||
?>
|
329
dibi/libs/interfaces.php
Normal file
329
dibi/libs/interfaces.php
Normal file
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* dibi - tiny'n'smart database abstraction layer
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "dibi license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://dibiphp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @license http://dibiphp.com/license dibi license
|
||||
* @link http://dibiphp.com
|
||||
* @package dibi
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for user variable, used for generating SQL.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDibiVariable
|
||||
{
|
||||
/**
|
||||
* Format for SQL.
|
||||
* @param DibiTranslator
|
||||
* @param string optional modifier
|
||||
* @return string SQL code
|
||||
*/
|
||||
function toSql(DibiTranslator $translator, $modifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides an interface between a dataset and data-aware components.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDataSource extends Countable, IteratorAggregate
|
||||
{
|
||||
//function IteratorAggregate::getIterator();
|
||||
//function Countable::count();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Defines method that must profiler implement.
|
||||
* @package dibi
|
||||
*/
|
||||
interface IDibiProfiler
|
||||
{
|
||||
/**#@+ event type */
|
||||
const CONNECT = 1;
|
||||
const SELECT = 4;
|
||||
const INSERT = 8;
|
||||
const DELETE = 16;
|
||||
const UPDATE = 32;
|
||||
const QUERY = 60;
|
||||
const BEGIN = 64;
|
||||
const COMMIT = 128;
|
||||
const ROLLBACK = 256;
|
||||
const TRANSACTION = 448;
|
||||
const EXCEPTION = 512;
|
||||
const ALL = 1023;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Before event notification.
|
||||
* @param DibiConnection
|
||||
* @param int event name
|
||||
* @param string sql
|
||||
* @return int
|
||||
*/
|
||||
function before(DibiConnection $connection, $event, $sql = NULL);
|
||||
|
||||
/**
|
||||
* After event notification.
|
||||
* @param int
|
||||
* @param DibiResult
|
||||
* @return void
|
||||
*/
|
||||
function after($ticket, $result = NULL);
|
||||
|
||||
/**
|
||||
* After exception notification.
|
||||
* @param DibiDriverException
|
||||
* @return void
|
||||
*/
|
||||
function exception(DibiDriverException $exception);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dibi driver interface.
|
||||
*
|
||||
* @author David Grudl
|
||||
* @copyright Copyright (c) 2005, 2008 David Grudl
|
||||
* @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 IDibiDriver|NULL
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function query($sql);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
|
||||
* @return int|FALSE number of rows or FALSE on error
|
||||
*/
|
||||
function affectedRows();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||
* @return int|FALSE int on success or FALSE on failure
|
||||
*/
|
||||
function insertId($sequence);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transaction (if supported).
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function begin();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commits statements in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function commit();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rollback changes in a transaction.
|
||||
* @return void
|
||||
* @throws DibiDriverException
|
||||
*/
|
||||
function rollback();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the connection resource.
|
||||
* @return mixed
|
||||
*/
|
||||
function getResource();
|
||||
|
||||
|
||||
|
||||
/********************* SQL ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encodes data for use in an SQL statement.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_TEXT, dibi::FIELD_BOOL, ...)
|
||||
* @return string encoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function escape($value, $type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decodes data from result set.
|
||||
* @param string value
|
||||
* @param string type (dibi::FIELD_BINARY)
|
||||
* @return string decoded value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function unescape($value, $type);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Injects LIMIT/OFFSET to the SQL query.
|
||||
* @param string &$sql The SQL query that will be modified.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
function applyLimit(&$sql, $limit, $offset);
|
||||
|
||||
|
||||
|
||||
/********************* result set ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result set.
|
||||
* @return int
|
||||
*/
|
||||
function rowCount();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Moves cursor position without fetching row.
|
||||
* @param int the 0-based cursor pos to seek to
|
||||
* @return boolean TRUE on success, FALSE if unable to seek to specified record
|
||||
* @throws DibiException
|
||||
*/
|
||||
function seek($row);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the row at current position and moves the internal cursor to the next position.
|
||||
* @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
|
||||
* @throws DibiException
|
||||
*/
|
||||
function getColumnsMeta();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the result set resource.
|
||||
* @return mixed
|
||||
*/
|
||||
function getResultResource();
|
||||
|
||||
|
||||
|
||||
/********************* reflection ****************d*g**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns list of tables.
|
||||
* @return array
|
||||
*/
|
||||
function getTables();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all columns in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
function getColumns($table);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all indexes in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
function getIndexes($table);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns metadata for all foreign keys in a table.
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
function getForeignKeys($table);
|
||||
|
||||
}
|
@@ -1,295 +0,0 @@
|
||||
<?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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
@@ -1,396 +0,0 @@
|
||||
<?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
|
||||
|
||||
|
||||
|
||||
?>
|
2
dibi/netterobots.txt
Normal file
2
dibi/netterobots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Disallow: /drivers
|
||||
Disallow: /Nette
|
608
examples/Nette/Debug.php
Normal file
608
examples/Nette/Debug.php
Normal file
@@ -0,0 +1,608 @@
|
||||
<?php
|
||||
/**
|
||||
* Nette Framework
|
||||
*
|
||||
* Copyright (c) 2004, 2008 David Grudl (http://davidgrudl.com)
|
||||
*
|
||||
* This source file is subject to the "Nette license" that is bundled
|
||||
* with this package in the file license.txt.
|
||||
*
|
||||
* For more information please see http://nettephp.com
|
||||
*
|
||||
* @copyright Copyright (c) 2004, 2008 David Grudl
|
||||
* @license http://nettephp.com/license Nette license
|
||||
* @link http://nettephp.com
|
||||
* @category Nette
|
||||
* @package Nette
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
class
|
||||
ArgumentOutOfRangeException
|
||||
extends
|
||||
InvalidArgumentException{}class
|
||||
InvalidStateException
|
||||
extends
|
||||
RuntimeException{}class
|
||||
NotImplementedException
|
||||
extends
|
||||
LogicException{}class
|
||||
NotSupportedException
|
||||
extends
|
||||
LogicException{}class
|
||||
MemberAccessException
|
||||
extends
|
||||
LogicException{}class
|
||||
IOException
|
||||
extends
|
||||
RuntimeException{}class
|
||||
FileNotFoundException
|
||||
extends
|
||||
IOException{}class
|
||||
DirectoryNotFoundException
|
||||
extends
|
||||
IOException{}class
|
||||
FatalErrorException
|
||||
extends
|
||||
Exception{public
|
||||
function
|
||||
__construct($message,$code,$severity,$file,$line,$context){parent::__construct($message,$code);$this->file=$file;$this->line=$line;$this->context=$context;}}final
|
||||
class
|
||||
Framework{const
|
||||
VERSION='0.8';const
|
||||
REVISION='107 released on 2008/10/29 20:40:23';final
|
||||
public
|
||||
function
|
||||
__construct(){throw
|
||||
new
|
||||
LogicException("Cannot instantiate static class ".get_class($this));}public
|
||||
static
|
||||
function
|
||||
compareVersion($version){return
|
||||
version_compare($version,self::VERSION);}public
|
||||
static
|
||||
function
|
||||
promo($xhtml=TRUE){echo'<a href="http://nettephp.com/" title="Nette Framework - The Most Innovative PHP Framework"><img ','src="http://nettephp.com/images/nette-powered.gif" alt="Powered by Nette Framework" width="80" height="15"',($xhtml?' />':'>'),'</a>';}}final
|
||||
class
|
||||
Debug{public
|
||||
static$counters=array();public
|
||||
static$html;public
|
||||
static$maxDepth=3;public
|
||||
static$maxLen=150;private
|
||||
static$enabled=FALSE;public
|
||||
static$useFirebug;private
|
||||
static$logFile;private
|
||||
static$logHandle;private
|
||||
static$sendEmails;private
|
||||
static$emailHeaders=array('To'=>'','From'=>'noreply@%host%','X-Mailer'=>'Nette Framework','Subject'=>'PHP: An error occurred on the server %host%','Body'=>'[%date%]');public
|
||||
static$mailer=array(__CLASS__,'sendEmail');public
|
||||
static$emailProbability=0.01;public
|
||||
static$keysToHide=array('password','passwd','pass','pwd','creditcard','credit card','cc','pin');private
|
||||
static$colophons=array(array(__CLASS__,'getDefaultColophons'));private
|
||||
static$keyFilter=array();public
|
||||
static$time;const
|
||||
LOG='LOG';const
|
||||
INFO='INFO';const
|
||||
WARN='WARN';const
|
||||
ERROR='ERROR';final
|
||||
public
|
||||
function
|
||||
__construct(){throw
|
||||
new
|
||||
LogicException("Cannot instantiate static class ".get_class($this));}public
|
||||
static
|
||||
function
|
||||
dump($var,$return=FALSE){self::$keyFilter=FALSE;$output="<pre class=\"dump\">".self::_dump($var,0)."</pre>\n";if(!self::$html){$output=htmlspecialchars_decode(strip_tags($output),ENT_NOQUOTES);}if($return){return$output;}else{echo$output;return$var;}}private
|
||||
static
|
||||
function
|
||||
_dump(&$var,$level){if(is_bool($var)){return"<span>bool</span>(".($var?'TRUE':'FALSE').")\n";}elseif($var===NULL){return"<span>NULL</span>\n";}elseif(is_int($var)){return"<span>int</span>($var)\n";}elseif(is_float($var)){return"<span>float</span>($var)\n";}elseif(is_string($var)){if(self::$maxLen&&strlen($var)>self::$maxLen){$s=htmlSpecialChars(substr($var,0,self::$maxLen),ENT_NOQUOTES).' ... ';}else{$s=htmlSpecialChars($var,ENT_NOQUOTES);}return"<span>string</span>(".strlen($var).") \"$s\"\n";}elseif(is_array($var)){$s="<span>array</span>(".count($var).") {\n";$space=str_repeat(' ',$level);static$marker;if($marker===NULL)$marker=uniqid("\x00",TRUE);if(isset($var[$marker])){$s.="$space *RECURSION*\n";}elseif($level<self::$maxDepth||!self::$maxDepth){$var[$marker]=0;foreach($var
|
||||
as$k=>&$v){if($k===$marker)continue;$s.="$space ".(is_int($k)?$k:"\"$k\"")." => ";if(self::$keyFilter&&is_string($v)&&isset(self::$keyFilter[strtolower($k)])){$s.="<span>string</span>(?) <i>*** hidden ***</i>\n";}else{$s.=self::_dump($v,$level+1);}}unset($var[$marker]);}else{$s.="$space ...\n";}return$s."$space}\n";}elseif(is_object($var)){$arr=(array)$var;$s="<span>object</span>(".get_class($var).") (".count($arr).") {\n";$space=str_repeat(' ',$level);static$list=array();if(in_array($var,$list,TRUE)){$s.="$space *RECURSION*\n";}elseif($level<self::$maxDepth||!self::$maxDepth){$list[]=$var;foreach($arr
|
||||
as$k=>&$v){$m='';if($k[0]==="\x00"){$m=$k[1]==='*'?' <span>protected</span>':' <span>private</span>';$k=substr($k,strrpos($k,"\x00")+1);}$s.="$space \"$k\"$m => ";if(self::$keyFilter&&is_string($v)&&isset(self::$keyFilter[strtolower($k)])){$s.="<span>string</span>(?) <i>*** hidden ***</i>\n";}else{$s.=self::_dump($v,$level+1);}}array_pop($list);}else{$s.="$space ...\n";}return$s."$space}\n";}elseif(is_resource($var)){return"<span>resource of type</span>(".get_resource_type($var).")\n";}else{return"<span>unknown type</span>\n";}}public
|
||||
static
|
||||
function
|
||||
timer(){static$time=0;$now=microtime(TRUE);$delta=$now-$time;$time=$now;return$delta;}public
|
||||
static
|
||||
function
|
||||
enable($level=E_ALL,$logErrors=NULL,$sendEmails=FALSE){if(version_compare(PHP_VERSION,'5.2.1')===0){throw
|
||||
new
|
||||
NotSupportedException(__METHOD__.' is not supported in PHP 5.2.1');}if($logErrors===NULL&&class_exists('Environment')){$logErrors=Environment::isLive();}if(self::$useFirebug===NULL){self::$useFirebug=function_exists('json_encode')&&!$logErrors&&isset($_SERVER['HTTP_USER_AGENT'])&&strpos($_SERVER['HTTP_USER_AGENT'],'FirePHP/');}if($level!==NULL){error_reporting($level);}if(function_exists('ini_set')){ini_set('display_startup_errors',!$logErrors);ini_set('display_errors',!$logErrors);ini_set('html_errors',self::$html);ini_set('log_errors',(bool)$logErrors);}elseif($logErrors){throw
|
||||
new
|
||||
NotSupportedException('Function ini_set() is not enabled.');}if($logErrors){if(is_string($logErrors)){self::$logFile=strpos($logErrors,'%')===FALSE?$logErrors:Environment::expand($logErrors);}else{try{self::$logFile=Environment::expand('%logDir%/php_error.log');}catch(InvalidStateException$e){self::$logFile='php_error.log';}}ini_set('error_log',self::$logFile);}self::$sendEmails=$logErrors&&$sendEmails;if(self::$sendEmails){if(is_string($sendEmails)){self::$emailHeaders['To']=$sendEmails;}elseif(is_array($sendEmails)){self::$emailHeaders=$sendEmails+self::$emailHeaders;}if(mt_rand()/mt_getrandmax()<self::$emailProbability){self::observeErrorLog();}}if(!defined('E_RECOVERABLE_ERROR')){define('E_RECOVERABLE_ERROR',4096);}if(!defined('E_DEPRECATED')){define('E_DEPRECATED',8192);}set_exception_handler(array(__CLASS__,'exceptionHandler'));set_error_handler(array(__CLASS__,'errorHandler'));self::$enabled=TRUE;}public
|
||||
static
|
||||
function
|
||||
isEnabled(){return
|
||||
self::$enabled;}public
|
||||
static
|
||||
function
|
||||
exceptionHandler(Exception$exception){if(!headers_sent()){header('HTTP/1.1 500 Internal Server Error');}if(self::$logFile){error_log("PHP Fatal error: Uncaught $exception");$file=@strftime('%d-%b-%Y %H-%M-%S ',Debug::$time).strstr(number_format(Debug::$time,4,'~',''),'~');$file=dirname(self::$logFile)."/exception $file.html";self::$logHandle=@fopen($file,'x');if(self::$logHandle){ob_start(array(__CLASS__,'writeFile'),1);self::paintBlueScreen($exception);ob_end_flush();fclose(self::$logHandle);}self::observeErrorLog();}elseif(!self::$html||isset($_SERVER['HTTP_X_REQUESTED_WITH'])&&$_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest'){if(self::$useFirebug&&!headers_sent()){self::fireLog($exception);}else{echo"$exception\n";foreach(self::$colophons
|
||||
as$callback){foreach((array)call_user_func($callback,'bluescreen')as$line)echo
|
||||
strip_tags($line)."\n";}}}else{while(ob_get_level()&&@ob_end_clean());self::paintBlueScreen($exception);exit;}}public
|
||||
static
|
||||
function
|
||||
errorHandler($severity,$message,$file,$line,$context){static$fatals=array(E_ERROR=>1,E_CORE_ERROR=>1,E_COMPILE_ERROR=>1,E_USER_ERROR=>1,E_PARSE=>1,E_RECOVERABLE_ERROR=>1);if(isset($fatals[$severity])){throw
|
||||
new
|
||||
FatalErrorException($message,0,$severity,$file,$line,$context);}elseif(($severity&error_reporting())!==$severity){return
|
||||
NULL;}elseif(self::$useFirebug&&!headers_sent()){$types=array(E_WARNING=>'Warning',E_USER_WARNING=>'Warning',E_NOTICE=>'Notice',E_USER_NOTICE=>'Notice',E_STRICT=>'Strict standards',E_DEPRECATED=>'Deprecated');$type=isset($types[$severity])?$types[$severity]:'Unknown error';$message=strip_tags($message);self::fireLog("$type: $message in $file on line $line",'WARN');return
|
||||
NULL;}return
|
||||
FALSE;}public
|
||||
static
|
||||
function
|
||||
paintBlueScreen(Exception$exception){$colophons=self::$colophons;function
|
||||
_netteDebugPrintCode($file,$line,$count=15){if(function_exists('ini_set')){ini_set('highlight.comment','#999; font-style: italic');ini_set('highlight.default','#000');ini_set('highlight.html','#06b');ini_set('highlight.keyword','#d24; font-weight: bold');ini_set('highlight.string','#080');}$start=max(1,$line-floor($count/2));$source=explode("\n",@highlight_file($file,TRUE));echo$source[0];$source=explode('<br />',$source[1]);array_unshift($source,NULL);$i=$start;while(--$i>=1){if(preg_match('#.*(</?span[^>]*>)#',$source[$i],$m)){if($m[1]!=='</span>')echo$m[1];break;}}$source=array_slice($source,$start,$count,TRUE);end($source);$numWidth=strlen((string)key($source));foreach($source
|
||||
as$n=>$s){$s=str_replace(array("\r","\n"),array('',''),$s);if($n===$line){printf("<span class='highlight'>Line %{$numWidth}s: %s\n</span>%s",$n,strip_tags($s),preg_replace('#[^>]*(<[^>]+>)[^<]*#','$1',$s));}else{printf("<span class='line'>Line %{$numWidth}s:</span> %s\n",$n,$s);}}echo'</span></span></code>';}function
|
||||
_netteOpenPanel($name,$collaped){static$id;$id++;?>
|
||||
<div class="panel">
|
||||
<h2><a href="#" onclick="return !toggle(this, 'pnl<?php echo$id?>')"><?php echo
|
||||
htmlSpecialChars($name)?> <span><?php echo$collaped?'▶':'▼'?></span></a></h2>
|
||||
|
||||
<div id="pnl<?php echo$id?>" class="<?php echo$collaped?'collapsed ':''?>inner">
|
||||
<?php
|
||||
}function
|
||||
_netteClosePanel(){?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}if(headers_sent()){echo'</pre></xmp></table>';}?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="robots" content="noindex,noarchive">
|
||||
<meta name="generator" content="Nette Framework">
|
||||
|
||||
<title><?php echo
|
||||
htmlspecialchars(get_class($exception))?></title>
|
||||
|
||||
<style type="text/css">
|
||||
/* <![CDATA[ */
|
||||
body {
|
||||
font: 78%/1.5 Verdana, sans-serif;
|
||||
background: white;
|
||||
color: #333;
|
||||
margin: 0 0 2em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal !important;
|
||||
font-size: 18pt;
|
||||
margin: .6em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 14pt;
|
||||
color: #888;
|
||||
margin: .6em 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #4197E3;
|
||||
}
|
||||
|
||||
a span {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
p { margin: .8em 0 }
|
||||
|
||||
pre, code, table {
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
|
||||
pre, table {
|
||||
background: #ffffcc;
|
||||
padding: .4em .7em;
|
||||
border: 1px dotted silver;
|
||||
}
|
||||
|
||||
table pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
pre.dump span {
|
||||
color: #c16549;
|
||||
}
|
||||
|
||||
div.panel {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 1px 2em;
|
||||
}
|
||||
|
||||
div.inner {
|
||||
padding: 0.1em 1em 1em;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
vertical-align: top;
|
||||
padding: 2px 3px;
|
||||
border: 1px solid #eeeebb;
|
||||
}
|
||||
|
||||
ul {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.highlight, #error {
|
||||
background: red;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.line {
|
||||
color: #9e9e7e;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* ]]> */
|
||||
</style>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
document.write('<style> .collapsed { display: none; } </style>');
|
||||
|
||||
function toggle(link, panel)
|
||||
{
|
||||
var span = link.getElementsByTagName('span')[0];
|
||||
var div = document.getElementById(panel);
|
||||
var collapsed = div.currentStyle ? div.currentStyle.display == 'none' : getComputedStyle(div, null).display == 'none';
|
||||
|
||||
span.innerHTML = String.fromCharCode(collapsed ? 0x25bc : 0x25b6);
|
||||
div.style.display = collapsed ? 'block' : 'none';
|
||||
|
||||
return true;
|
||||
}
|
||||
/* ]]> */
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
<div id="error" class="panel">
|
||||
<h1><?php echo
|
||||
htmlspecialchars(get_class($exception)),($exception->getCode()?' #'.$exception->getCode():'')?></h1>
|
||||
|
||||
<p><?php echo
|
||||
htmlspecialchars($exception->getMessage())?></p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<?php $ex=$exception;$level=0;?>
|
||||
<?php do{?>
|
||||
|
||||
<?php if($level++):?>
|
||||
<?php _netteOpenPanel('Caused by',TRUE)?>
|
||||
<div class="panel">
|
||||
<h1><?php echo
|
||||
htmlspecialchars(get_class($ex)),($ex->getCode()?' #'.$ex->getCode():'')?></h1>
|
||||
|
||||
<p><?php echo
|
||||
htmlspecialchars($ex->getMessage())?></p>
|
||||
</div>
|
||||
<?php endif?>
|
||||
|
||||
<?php if(is_file($ex->getFile())):?>
|
||||
<?php _netteOpenPanel('Source file',FALSE)?>
|
||||
<p><strong>File:</strong> <?php echo
|
||||
htmlspecialchars($ex->getFile())?> <strong>Line:</strong> <?php echo$ex->getLine()?></p>
|
||||
<pre><?php _netteDebugPrintCode($ex->getFile(),$ex->getLine())?></pre>
|
||||
<?php _netteClosePanel()?>
|
||||
<?php endif?>
|
||||
|
||||
|
||||
|
||||
<?php _netteOpenPanel('Call stack',FALSE)?>
|
||||
<ol>
|
||||
<?php foreach($ex->getTrace()as$key=>$row):?>
|
||||
<li><p>
|
||||
|
||||
<?php if(isset($row['file'])):?>
|
||||
<span title="<?php echo
|
||||
htmlSpecialChars($row['file'])?>"><?php echo
|
||||
htmlSpecialChars(basename(dirname($row['file']))),'/<b>',htmlSpecialChars(basename($row['file'])),'</b></span> (',$row['line'],')'?>
|
||||
<?php else:?>
|
||||
<PHP inner-code>
|
||||
<?php endif?>
|
||||
|
||||
<?php if(isset($row['file'])&&is_file($row['file'])):?><a href="#" onclick="return !toggle(this, 'src<?php echo"$level-$key"?>')">source <span>▶</span></a> <?php endif?>
|
||||
|
||||
<?php if(isset($row['class']))echo$row['class'].$row['type']?>
|
||||
<?php echo$row['function']?>
|
||||
|
||||
(<?php if(!empty($row['args'])):?><a href="#" onclick="return !toggle(this, 'args<?php echo"$level-$key"?>')">arguments <span>▶</span></a><?php endif?>)
|
||||
</p>
|
||||
|
||||
<?php if(!empty($row['args'])):?>
|
||||
<div class="collapsed" id="args<?php echo"$level-$key"?>">
|
||||
<table>
|
||||
<?php
|
||||
|
||||
try{$r=isset($row['class'])?new
|
||||
ReflectionMethod($row['class'],$row['function']):new
|
||||
ReflectionFunction($row['function']);$params=$r->getParameters();}catch(Exception$e){$params=array();}foreach($row['args']as$k=>$v){echo'<tr><td>',(isset($params[$k])?'$'.$params[$k]->name:"#$k"),'</td>';echo'<td>',self::safeDump($v,isset($params[$k])?$params[$k]->name:NULL),"</td></tr>\n";}?>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif?>
|
||||
|
||||
|
||||
<?php if(isset($row['file'])&&is_file($row['file'])):?>
|
||||
<pre class="collapsed" id="src<?php echo"$level-$key"?>"><?php _netteDebugPrintCode($row['file'],$row['line'])?></pre>
|
||||
<?php endif?>
|
||||
|
||||
</li>
|
||||
<?php endforeach?>
|
||||
</ol>
|
||||
<?php _netteClosePanel()?>
|
||||
|
||||
|
||||
|
||||
<?php if($ex
|
||||
instanceof
|
||||
IDebuggable):?>
|
||||
<?php foreach($ex->getPanels()as$name=>$panel):?>
|
||||
<?php _netteOpenPanel($name,empty($panel['expanded']))?>
|
||||
<?php echo$panel['content']?>
|
||||
<?php _netteClosePanel()?>
|
||||
<?php endforeach?>
|
||||
<?php endif?>
|
||||
|
||||
|
||||
|
||||
<?php if(isset($ex->context)&&is_array($ex->context)):?>
|
||||
<?php _netteOpenPanel('Variables',TRUE)?>
|
||||
<table>
|
||||
<?php
|
||||
|
||||
foreach($ex->context
|
||||
as$k=>$v){echo'<tr><td>$',htmlspecialchars($k),'</td><td>',self::safeDump($v,$k),"</td></tr>\n";}?>
|
||||
</table>
|
||||
<?php _netteClosePanel()?>
|
||||
<?php endif?>
|
||||
|
||||
<?php }while((method_exists($ex,'getPrevious')&&$ex=$ex->getPrevious())||(isset($ex->previous)&&$ex=$ex->previous));?>
|
||||
<?php while(--$level)_netteClosePanel()?>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<?php _netteOpenPanel('Environment',TRUE)?>
|
||||
<?php
|
||||
$list=get_defined_constants(TRUE);if(!empty($list['user'])):?>
|
||||
<h3><a href="#" onclick="return !toggle(this, 'pnl-env-const')">Constants <span>▼</span></a></h3>
|
||||
<table id="pnl-env-const">
|
||||
<?php
|
||||
|
||||
foreach($list['user']as$k=>$v){echo'<tr><td>',htmlspecialchars($k),'</td><td>',self::safeDump($v,$k),"</td></tr>\n";}?>
|
||||
</table>
|
||||
<?php endif?>
|
||||
|
||||
|
||||
<h3><a href="#" onclick="return !toggle(this, 'pnl-env-files')">Included files <span>▶</span></a> (<?php echo
|
||||
count(get_included_files())?>)</h3>
|
||||
<table id="pnl-env-files" class="collapsed">
|
||||
<?php
|
||||
|
||||
foreach(get_included_files()as$v){echo'<tr><td>',htmlspecialchars($v),"</td></tr>\n";}?>
|
||||
</table>
|
||||
|
||||
|
||||
<h3>$_SERVER</h3>
|
||||
<?php if(empty($_SERVER)):?>
|
||||
<p><i>empty</i></p>
|
||||
<?php else:?>
|
||||
<table>
|
||||
<?php
|
||||
|
||||
foreach($_SERVER
|
||||
as$k=>$v)echo'<tr><td>',htmlspecialchars($k),'</td><td>',self::dump($v,TRUE),"</td></tr>\n";?>
|
||||
</table>
|
||||
<?php endif?>
|
||||
<?php _netteClosePanel()?>
|
||||
|
||||
|
||||
|
||||
|
||||
<?php _netteOpenPanel('HTTP request',TRUE)?>
|
||||
<?php if(function_exists('apache_request_headers')):?>
|
||||
<h3>Headers</h3>
|
||||
<table>
|
||||
<?php
|
||||
|
||||
foreach(apache_request_headers()as$k=>$v)echo'<tr><td>',htmlspecialchars($k),'</td><td>',htmlspecialchars($v),"</td></tr>\n";?>
|
||||
</table>
|
||||
<?php endif?>
|
||||
|
||||
|
||||
<?php foreach(array('_GET','_POST','_COOKIE')as$name):?>
|
||||
<h3>$<?php echo$name?></h3>
|
||||
<?php if(empty($GLOBALS[$name])):?>
|
||||
<p><i>empty</i></p>
|
||||
<?php else:?>
|
||||
<table>
|
||||
<?php
|
||||
|
||||
foreach($GLOBALS[$name]as$k=>$v)echo'<tr><td>',htmlspecialchars($k),'</td><td>',self::dump($v,TRUE),"</td></tr>\n";?>
|
||||
</table>
|
||||
<?php endif?>
|
||||
<?php endforeach?>
|
||||
<?php _netteClosePanel()?>
|
||||
|
||||
|
||||
|
||||
<?php _netteOpenPanel('HTTP response',TRUE)?>
|
||||
<h3>Headers</h3>
|
||||
<?php if(headers_list()):?>
|
||||
<pre><?php
|
||||
|
||||
foreach(headers_list()as$s)echo
|
||||
htmlspecialchars($s),'<br>';?></pre>
|
||||
<?php else:?>
|
||||
<p><i>no headers</i></p>
|
||||
<?php endif?>
|
||||
<?php _netteClosePanel()?>
|
||||
|
||||
|
||||
<ul>
|
||||
<?php foreach($colophons
|
||||
as$callback):?>
|
||||
<?php foreach((array)call_user_func($callback,'bluescreen')as$line):?><li><?php echo$line,"\n"?></li><?php endforeach?>
|
||||
<?php endforeach?>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html><?php }public
|
||||
static
|
||||
function
|
||||
writeFile($buffer){fwrite(self::$logHandle,$buffer);}private
|
||||
static
|
||||
function
|
||||
observeErrorLog(){if(!self::$sendEmails)return;$monitorFile=self::$logFile.'.monitor';$saved=@file_get_contents($monitorFile);$actual=(int)@filemtime(self::$logFile);if($saved===FALSE){file_put_contents($monitorFile,$actual);}elseif(is_numeric($saved)&&$saved!=$actual){if(file_put_contents($monitorFile,'e-mail has been sent')){call_user_func(self::$mailer);}}}private
|
||||
static
|
||||
function
|
||||
sendEmail(){$host=isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:(isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:'');$headers=str_replace(array('%host%','%date%'),array($host,@date('Y-m-d H:i:s',Debug::$time)),self::$emailHeaders);$subject=$headers['Subject'];$to=$headers['To'];$body=$headers['Body'];unset($headers['Subject'],$headers['To'],$headers['Body']);$header='';foreach($headers
|
||||
as$key=>$value){$header.="$key: $value\r\n";}$body=str_replace("\r\n","\n",$body);if(PHP_OS!='Linux')$body=str_replace("\n","\r\n",$body);if($to==='debug'){self::dump(array($to,$subject,$body,$header));}else{mail($to,$subject,$body,$header);}}private
|
||||
static
|
||||
function
|
||||
safeDump($var,$key=NULL){self::$keyFilter=array_change_key_case(array_flip(self::$keysToHide),CASE_LOWER);if($key!==NULL&&isset(self::$keyFilter[strtolower($key)])){return'<i>*** hidden ***</i>';}return"<pre class=\"dump\">".self::_dump($var,0)."</pre>\n";}public
|
||||
static
|
||||
function
|
||||
enableProfiler(){register_shutdown_function(array(__CLASS__,'paintProfiler'));}public
|
||||
static
|
||||
function
|
||||
paintProfiler(){$colophons=self::$colophons;if(self::$useFirebug){foreach(self::$colophons
|
||||
as$callback){foreach((array)call_user_func($callback,'profiler')as$line)self::fireLog(strip_tags($line));}}if(!isset($_SERVER['HTTP_X_REQUESTED_WITH'])||$_SERVER['HTTP_X_REQUESTED_WITH']!=='XMLHttpRequest'){?>
|
||||
</pre></xmp>
|
||||
|
||||
<style type="text/css">
|
||||
/* <![CDATA[ */
|
||||
#netteProfilerContainer {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
#netteProfiler {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 1px;
|
||||
width: 350px;
|
||||
color: black;
|
||||
background: #EEE;
|
||||
border: 1px dotted gray;
|
||||
cursor: move;
|
||||
opacity: .70;
|
||||
=filter: alpha(opacity=70);
|
||||
}
|
||||
|
||||
#netteProfiler:hover {
|
||||
opacity: 1;
|
||||
=filter: none;
|
||||
}
|
||||
|
||||
#netteProfiler li {
|
||||
margin: 0;
|
||||
padding: 1px;
|
||||
font: normal normal 11px/1.4 Consolas, Arial;
|
||||
text-align: left;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#netteProfiler span[title] {
|
||||
border-bottom: 1px dotted gray;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
#netteProfiler strong {
|
||||
color: red;
|
||||
}
|
||||
/* ]]> */
|
||||
</style>
|
||||
|
||||
|
||||
<div id="netteProfilerContainer">
|
||||
<ul id="netteProfiler">
|
||||
<?php foreach($colophons
|
||||
as$callback):?>
|
||||
<?php foreach((array)call_user_func($callback,'profiler')as$line):?><li><?php echo$line,"\n"?></li><?php endforeach?>
|
||||
<?php endforeach?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
document.getElementById('netteProfiler').onmousedown = function(e) {
|
||||
e = e || event;
|
||||
this.posX = parseInt(this.style.left + '0');
|
||||
this.posY = parseInt(this.style.top + '0');
|
||||
this.mouseX = e.clientX;
|
||||
this.mouseY = e.clientY;
|
||||
|
||||
var thisObj = this;
|
||||
|
||||
document.documentElement.onmousemove = function(e) {
|
||||
e = e || event;
|
||||
thisObj.style.left = (e.clientX - thisObj.mouseX + thisObj.posX) + "px";
|
||||
thisObj.style.top = (e.clientY - thisObj.mouseY + thisObj.posY) + "px";
|
||||
return false;
|
||||
};
|
||||
|
||||
document.documentElement.onmouseup = function(e) {
|
||||
document.documentElement.onmousemove = null;
|
||||
document.documentElement.onmouseup = null;
|
||||
return false;
|
||||
};
|
||||
};
|
||||
/* ]]> */
|
||||
</script>
|
||||
<?php }}public
|
||||
static
|
||||
function
|
||||
addColophon($callback){if(!in_array($callback,self::$colophons,TRUE)&&is_callable($callback)){self::$colophons[]=$callback;}}public
|
||||
static
|
||||
function
|
||||
getDefaultColophons($sender){if($sender==='profiler'){$arr[]='Elapsed time: '.sprintf('%0.3f',(microtime(TRUE)-Debug::$time)*1000).' ms';foreach((array)self::$counters
|
||||
as$name=>$value){if(is_array($value))$value=implode(', ',$value);$arr[]=htmlSpecialChars($name).' = <strong>'.htmlSpecialChars($value).'</strong>';}$autoloaded=class_exists('AutoLoader',FALSE)?AutoLoader::$count:0;$s='<span>'.count(get_included_files()).'/'.$autoloaded.' files</span>, ';$exclude=array('stdClass','Exception','ErrorException','Traversable','IteratorAggregate','Iterator','ArrayAccess','Serializable','Closure');foreach(get_loaded_extensions()as$ext){$ref=new
|
||||
ReflectionExtension($ext);$exclude=array_merge($exclude,$ref->getClassNames());}$classes=array_diff(get_declared_classes(),$exclude);$intf=array_diff(get_declared_interfaces(),$exclude);$func=get_defined_functions();$func=(array)@$func['user'];$consts=get_defined_constants(TRUE);$consts=array_keys((array)@$consts['user']);foreach(array('classes','intf','func','consts')as$item){$s.='<span '.($$item?'title="'.implode(", ",$$item).'"':'').'>'.count($$item).' '.$item.'</span>, ';}$arr[]=$s;}if($sender==='bluescreen'){$arr[]='PHP '.PHP_VERSION;if(isset($_SERVER['SERVER_SOFTWARE']))$arr[]=htmlSpecialChars($_SERVER['SERVER_SOFTWARE']);$arr[]='Nette Framework '.Framework::VERSION.' (revision '.Framework::REVISION.')';$arr[]='Report generated at '.@strftime('%c',Debug::$time);}return$arr;}public
|
||||
static
|
||||
function
|
||||
fireDump($var,$key){return
|
||||
self::fireSend(2,array((string)$key=>$var));}public
|
||||
static
|
||||
function
|
||||
fireLog($message,$priority=self::LOG,$label=NULL){if($message
|
||||
instanceof
|
||||
Exception){$priority='TRACE';$message=array('Class'=>get_class($message),'Message'=>$message->getMessage(),'File'=>$message->getFile(),'Line'=>$message->getLine(),'Trace'=>self::replaceObjects($message->getTrace()));}elseif($priority==='GROUP_START'){$label=$message;$message=NULL;}return
|
||||
self::fireSend(1,array(array('Type'=>$priority,'Label'=>$label),self::replaceObjects($message)));}private
|
||||
static
|
||||
function
|
||||
fireSend($index,$payload){if(headers_sent())return
|
||||
FALSE;header('X-Wf-Protocol-nette: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');header('X-Wf-nette-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');if($index===1){header('X-Wf-nette-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');}elseif($index===2){header('X-Wf-nette-Structure-2: http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');}$payload=json_encode($payload);static$counter;foreach(str_split($payload,4990)as$s){$num=++$counter;header("X-Wf-nette-$index-1-n$num: |$s|\\");}header("X-Wf-nette-$index-1-n$num: |$s|");header("X-Wf-nette-Index: n$num");return
|
||||
TRUE;}static
|
||||
private
|
||||
function
|
||||
replaceObjects($val){if(is_object($val)){return'object '.get_class($val).'';}elseif(is_array($val)){foreach($val
|
||||
as$k=>$v){unset($val[$k]);$val[$k]=self::replaceObjects($v);}}return$val;}}Debug::$html=PHP_SAPI!=='cli';Debug::$time=microtime(TRUE);
|
62
examples/Nette/license.txt
Normal file
62
examples/Nette/license.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
The Nette License, Version 1
|
||||
============================
|
||||
|
||||
Copyright (c) 2004, 2008 David Grudl (http://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
This license is a legal agreement between you and David Grudl (the "Author")
|
||||
for the use of Nette Framework (the "Software"). By obtaining, using and/or
|
||||
copying the Software, you agree that you have read, understood, and will
|
||||
comply with the terms and conditions of this license.
|
||||
|
||||
|
||||
PERMITTED USE
|
||||
-------------
|
||||
|
||||
You are permitted to use, copy, modify, and distribute the Software and its
|
||||
documentation, with or without modification, for any purpose, provided that
|
||||
the following conditions are met:
|
||||
|
||||
1. A copy of this license agreement must be included with the distribution.
|
||||
|
||||
2. Redistributions of source code must retain the above copyright notice in
|
||||
all source code files.
|
||||
|
||||
3. Redistributions in binary form must reproduce the above copyright notice
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
4. Products derived from the Software must include an acknowledgment that
|
||||
they are derived from Nette Framework in their documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
5. The name "Nette Framework" must not be used to endorse or promote products
|
||||
derived from the Software without prior written permission from Author.
|
||||
|
||||
6. Products derived from the Software may not be called "Nette Framework",
|
||||
nor may "Nette" appear in their name, without prior written
|
||||
permission from Author.
|
||||
|
||||
|
||||
INDEMNITY
|
||||
---------
|
||||
|
||||
You agree to indemnify and hold harmless the Author and any contributors
|
||||
for any direct, indirect, incidental, or consequential third-party claims,
|
||||
actions or suits, as well as any related expenses, liabilities, damages,
|
||||
settlements or fees arising from your use or misuse of the Software,
|
||||
or a violation of any terms of this license.
|
||||
|
||||
|
||||
DISCLAIMER OF WARRANTY
|
||||
----------------------
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "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 HOLDER 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.
|
3
examples/Nette/readme.txt
Normal file
3
examples/Nette/readme.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
This file is part of Nette Framework
|
||||
|
||||
For more information please see http://nettephp.com
|
31
examples/apply-limit.php
Normal file
31
examples/apply-limit.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<h1>dibi apply limit/offset example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
// no limit
|
||||
dibi::test('SELECT * FROM [products]');
|
||||
// -> SELECT * FROM [products]
|
||||
|
||||
|
||||
echo '<hr>';
|
||||
|
||||
// with limit = 2
|
||||
dibi::test('SELECT * FROM [products] %lmt', 2);
|
||||
// -> SELECT * FROM [products] LIMIT 2
|
||||
|
||||
|
||||
echo '<hr>';
|
||||
|
||||
// with limit = 2, offset = 1
|
||||
dibi::test('SELECT * FROM [products] %lmt %ofs', 2, 1);
|
||||
// -> SELECT * FROM [products] LIMIT 2 OFFSET 1
|
@@ -1,40 +1,145 @@
|
||||
<?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();
|
||||
|
||||
|
||||
|
||||
?>
|
||||
<h1>dibi::connect() example</h1>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
// connects to SQlite
|
||||
echo '<p>Connecting to Sqlite: ';
|
||||
try {
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
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=utf8');
|
||||
echo 'OK';
|
||||
|
||||
} catch (DibiException $e) {
|
||||
echo get_class($e), ': ', $e->getMessage(), "\n";
|
||||
}
|
||||
echo "</p>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
// connects to MySQLi using array
|
||||
echo '<p>Connecting to MySQL: ';
|
||||
try {
|
||||
dibi::connect(array(
|
||||
'driver' => 'mysqli',
|
||||
'host' => 'localhost',
|
||||
'username' => 'root',
|
||||
'password' => 'xxx',
|
||||
'database' => 'dibi',
|
||||
'charset' => 'utf8',
|
||||
));
|
||||
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='.dirname(__FILE__).'/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 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";
|
30
examples/datetime.demo.php
Normal file
30
examples/datetime.demo.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<h1>IDibiVariable example</h1>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
// required since PHP 5.1.0
|
||||
date_default_timezone_set('Europe/Prague');
|
||||
|
||||
|
||||
|
||||
// CHANGE TO REAL PARAMETERS!
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
'formatDate' => "'Y-m-d'",
|
||||
'formatDateTime' => "'Y-m-d H-i-s'",
|
||||
));
|
||||
|
||||
|
||||
|
||||
// generate and dump SQL
|
||||
dibi::test("
|
||||
INSERT INTO [mytable]", array(
|
||||
'id' => 123,
|
||||
'date' => dibi::date('12.3.2007'),
|
||||
'stamp' => dibi::dateTime('23.1.2007 10:23'),
|
||||
));
|
||||
// -> INSERT INTO [mytable] ([id], [date], [stamp]) VALUES (123, '2007-03-12', '2007-01-23 10-23-00')
|
101
examples/dibi.table.php
Normal file
101
examples/dibi.table.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<h1>DibiTableX demo</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
dibi::begin();
|
||||
|
||||
|
||||
// autodetection: primary keys are customer_id, order_id, ...
|
||||
DibiTableX::$primaryMask = '%s_id';
|
||||
|
||||
|
||||
// table products
|
||||
class Products extends DibiTableX
|
||||
{
|
||||
// rely on autodetection...
|
||||
// protected $name = 'products';
|
||||
// protected $primary = 'product_id';
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// create table object
|
||||
$products = new Products;
|
||||
|
||||
echo "Table name: $products->name\n";
|
||||
echo "Primary key: $products->primary\n";
|
||||
|
||||
|
||||
// Finds rows by primary key
|
||||
foreach ($products->find(1, 3) as $row) {
|
||||
Debug::dump($row);
|
||||
}
|
||||
|
||||
|
||||
// select all
|
||||
$products->findAll()->dump();
|
||||
|
||||
|
||||
// select all, order by title, product_id
|
||||
$products->findAll('title', $products->primary)->dump();
|
||||
$products->findAll(array('title' => 'Chair'), 'title')->dump();
|
||||
|
||||
|
||||
// fetches single row with id 3
|
||||
$row = $products->fetch(3);
|
||||
|
||||
|
||||
// deletes row from a table
|
||||
$count = $products->delete(1);
|
||||
|
||||
// deletes multiple rows
|
||||
$count = $products->delete(array(1, 2, 3));
|
||||
Debug::dump($count); // number of deleted rows
|
||||
|
||||
|
||||
// update row #2 in a table
|
||||
$data = (object) NULL;
|
||||
$data->title = 'New title';
|
||||
$count = $products->update(2, $data);
|
||||
Debug::dump($count); // number of updated rows
|
||||
|
||||
|
||||
// update multiple rows in a table
|
||||
$count = $products->update(array(3, 5), $data);
|
||||
Debug::dump($count); // number of updated rows
|
||||
|
||||
|
||||
// inserts row into a table
|
||||
$data = array();
|
||||
$data['title'] = 'New product';
|
||||
$id = $products->insert($data);
|
||||
Debug::dump($id); // generated id
|
||||
|
||||
|
||||
// inserts or updates row into a table
|
||||
$data = array();
|
||||
$data['title'] = 'New product';
|
||||
$data[$products->primary] = 5;
|
||||
$products->insertOrUpdate($data);
|
||||
|
||||
|
||||
// is absolutely SQL injection safe
|
||||
$key = '3 OR 1=1';
|
||||
$products->delete($key);
|
||||
// --> DELETE FROM [products] WHERE [product_id] IN ( 3 )
|
||||
|
||||
|
||||
// select all using fluent interface
|
||||
Debug::dump($products->select('*')->orderBy('title')->fetchAll());
|
33
examples/dump.php
Normal file
33
examples/dump.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<h1>dibi dump example</h1>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
|
||||
$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();
|
||||
// -> SELECT * FROM [products] INNER JOIN [orders] USING ([product_id]) INNER JOIN [customers] USING ([customer_id])
|
||||
|
||||
|
||||
// dump result table
|
||||
echo '<h2>DibiResult::dump()</h2>';
|
||||
|
||||
$res->dump();
|
||||
// -> [table]
|
28
examples/extension.method.php
Normal file
28
examples/extension.method.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<h1>dibi extension method example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
|
||||
// using the "prototype" to add custom method to class DibiResult
|
||||
function DibiResult_prototype_fetchShuffle(DibiResult $obj)
|
||||
{
|
||||
$all = $obj->fetchAll();
|
||||
shuffle($all);
|
||||
return $all;
|
||||
}
|
||||
|
||||
|
||||
// fetch complete result set shuffled
|
||||
$res = dibi::query('SELECT * FROM [customers]');
|
||||
$all = $res->fetchShuffle();
|
||||
Debug::dump($all);
|
@@ -1,52 +1,94 @@
|
||||
<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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
?>
|
||||
<h1>dibi fetch example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
/*
|
||||
TABLE products
|
||||
|
||||
product_id | title
|
||||
-----------+----------
|
||||
1 | Chair
|
||||
2 | Table
|
||||
3 | Computer
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// fetch a single row
|
||||
$row = dibi::fetch('SELECT title FROM [products]');
|
||||
Debug::dump($row); // Chair
|
||||
echo '<hr>';
|
||||
|
||||
|
||||
// fetch a single value
|
||||
$value = dibi::fetchSingle('SELECT [title] FROM [products]');
|
||||
Debug::dump($value); // Chair
|
||||
echo '<hr>';
|
||||
|
||||
|
||||
// fetch complete result set
|
||||
$all = dibi::fetchAll('SELECT * FROM [products]');
|
||||
Debug::dump($all);
|
||||
echo '<hr>';
|
||||
|
||||
|
||||
// fetch complete result set like association array
|
||||
$res = dibi::query('SELECT * FROM [products]');
|
||||
$assoc = $res->fetchAssoc('title'); // key
|
||||
Debug::dump($assoc);
|
||||
echo '<hr>';
|
||||
|
||||
|
||||
// fetch complete result set like pairs key => value
|
||||
$pairs = $res->fetchPairs('product_id', 'title');
|
||||
Debug::dump($pairs);
|
||||
echo '<hr>';
|
||||
|
||||
|
||||
// fetch row by row
|
||||
foreach ($res as $n => $row) {
|
||||
Debug::dump($row);
|
||||
}
|
||||
echo '<hr>';
|
||||
|
||||
|
||||
// fetch row by row with defined offset
|
||||
foreach ($res->getIterator(2) as $n => $row) {
|
||||
Debug::dump($row);
|
||||
}
|
||||
|
||||
// fetch row by row with defined offset and limit
|
||||
foreach ($res->getIterator(2, 1) as $n => $row) {
|
||||
Debug::dump($row);
|
||||
}
|
||||
|
||||
|
||||
// more complex association array
|
||||
$res = dibi::query('
|
||||
SELECT *
|
||||
FROM [products]
|
||||
INNER JOIN [orders] USING ([product_id])
|
||||
INNER JOIN [customers] USING ([customer_id])
|
||||
');
|
||||
|
||||
$assoc = $res->fetchAssoc('customers.name,products.title'); // key
|
||||
Debug::dump($assoc);
|
||||
echo '<hr>';
|
||||
|
||||
$assoc = $res->fetchAssoc('customers.name,#,products.title'); // key
|
||||
Debug::dump($assoc);
|
||||
echo '<hr>';
|
||||
|
||||
$assoc = $res->fetchAssoc('customers.name,=,products.title'); // key
|
||||
Debug::dump($assoc);
|
||||
echo '<hr>';
|
||||
|
91
examples/fluent.test.php
Normal file
91
examples/fluent.test.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<h1>dibi dump example</h1>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
$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]
|
||||
|
||||
|
||||
|
||||
echo "\n";
|
||||
|
||||
// SELECT ...
|
||||
echo dibi::select('title')->as('id')
|
||||
->from('products')
|
||||
->fetchSingle();
|
||||
// -> Chair (as result of query: SELECT [title] AS [id] FROM [products])
|
||||
|
||||
|
||||
|
||||
echo "\n";
|
||||
|
||||
// INSERT ...
|
||||
dibi::insert('products', $record)
|
||||
->setFlag('IGNORE')
|
||||
->test();
|
||||
// -> INSERT IGNORE INTO [products] ([title], [price], [active]) VALUES ('Super product', 318, 1)
|
||||
|
||||
|
||||
|
||||
echo "\n";
|
||||
|
||||
// UPDATE ...
|
||||
dibi::update('products', $record)
|
||||
->where('product_id = %d', $id)
|
||||
->test();
|
||||
// -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
|
||||
|
||||
|
||||
|
||||
echo "\n";
|
||||
|
||||
// DELETE ...
|
||||
dibi::delete('products')
|
||||
->where('product_id = %d', $id)
|
||||
->test();
|
||||
// -> DELETE FROM [products] WHERE product_id = 10
|
||||
|
||||
|
||||
|
||||
echo "\n";
|
||||
|
||||
// custom commands
|
||||
dibi::command()
|
||||
->update('products')
|
||||
->where('product_id = %d', $id)
|
||||
->set($record)
|
||||
->test();
|
||||
// -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
|
||||
|
||||
|
||||
|
||||
echo "\n";
|
||||
|
||||
dibi::command()
|
||||
->truncate('products')
|
||||
->test();
|
||||
// -> TRUNCATE [products]
|
17
examples/load-sql-dump.php
Normal file
17
examples/load-sql-dump.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<h1>dibi import SQL dump example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
$count = dibi::loadFile('compress.zlib://sample.dump.sql.gz');
|
||||
|
||||
echo 'Number of SQL commands:', $count;
|
@@ -1,14 +0,0 @@
|
||||
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
|
||||
|
34
examples/logger.php
Normal file
34
examples/logger.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<h1>dibi logger example</h1>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
'profiler' => TRUE,
|
||||
));
|
||||
|
||||
|
||||
// enable log to this file
|
||||
dibi::getProfiler()->setFile('log.sql');
|
||||
|
||||
|
||||
|
||||
try {
|
||||
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] = %i', 1);
|
||||
|
||||
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < %i', 5);
|
||||
|
||||
$res = dibi::query('SELECT FROM [customers] WHERE [customer_id] < %i', 38);
|
||||
|
||||
} catch (DibiException $e) {
|
||||
echo '<p>', get_class($e), ': ', $e->getMessage(), '</p>';
|
||||
}
|
||||
|
||||
|
||||
echo "<h2>File log.sql:</h2>";
|
||||
|
||||
echo '<pre>', file_get_contents('log.sql'), '</pre>';
|
@@ -1,31 +0,0 @@
|
||||
<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);
|
||||
|
||||
|
||||
?>
|
@@ -1,34 +1,28 @@
|
||||
<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);
|
||||
|
||||
|
||||
?>
|
||||
<h1>dibi metatypes example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
$res = dibi::query('SELECT * FROM [customers]');
|
||||
|
||||
// auto-converts this column to integer
|
||||
$res->setType('customer_id', Dibi::FIELD_INTEGER);
|
||||
$res->setType('added', Dibi::FIELD_DATETIME, 'H:i j.n.Y');
|
||||
|
||||
$row = $res->fetch();
|
||||
Debug::dump($row);
|
||||
// outputs:
|
||||
// object(DibiRow)#3 (3) {
|
||||
// customer_id => int(1)
|
||||
// name => string(11) "Dave Lister"
|
||||
// added => string(15) "17:20 11.3.2007"
|
||||
// }
|
||||
|
28
examples/nette-debug.php
Normal file
28
examples/nette-debug.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<h1>Nette::Debug & dibi example</h1>
|
||||
|
||||
|
||||
<p>Dibi can display and log exceptions via Nette::Debug, part of Nette Framework.</p>
|
||||
|
||||
<ul>
|
||||
<li>Nette Framework: http://nettephp.com
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
// enable Nette::Debug
|
||||
Debug::enable();
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
|
||||
// throws error
|
||||
dibi::query('SELECT FROM [customers] WHERE [customer_id] < %i', 38);
|
36
examples/profiler.php
Normal file
36
examples/profiler.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
'profiler' => TRUE,
|
||||
));
|
||||
|
||||
|
||||
for ($i=0; $i<20; $i++) {
|
||||
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < %i', $i);
|
||||
}
|
||||
|
||||
?>
|
||||
<h1>Dibi profiler example</h1>
|
||||
|
||||
<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>
|
BIN
examples/sample.dump.sql.gz
Normal file
BIN
examples/sample.dump.sql.gz
Normal file
Binary file not shown.
BIN
examples/sample.mdb
Normal file
BIN
examples/sample.mdb
Normal file
Binary file not shown.
BIN
examples/sample.sdb
Normal file
BIN
examples/sample.sdb
Normal file
Binary file not shown.
@@ -1,48 +1,90 @@
|
||||
<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");
|
||||
|
||||
?>
|
||||
<style>
|
||||
pre.dibi { padding-bottom: 10px; }
|
||||
</style>
|
||||
<h1>dibi SQL builder example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
// required since PHP 5.1.0
|
||||
date_default_timezone_set('Europe/Prague');
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
// 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' => dibi::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]=%i", 123);
|
||||
// -> UPDATE [colors] SET [color]='blue', [order]=12 WHERE [id]=123
|
||||
|
||||
|
||||
|
||||
// SELECT
|
||||
$ipMask = '192.168.%';
|
||||
$timestamp = mktime(0, 0, 0, 10, 13, 1997);
|
||||
|
||||
dibi::test('
|
||||
SELECT COUNT(*) as [count]
|
||||
FROM [comments]
|
||||
WHERE [ip] LIKE %s', $ipMask, '
|
||||
AND [date] > ', dibi::date($timestamp)
|
||||
);
|
||||
// -> SELECT COUNT(*) as [count] FROM [comments] WHERE [ip] LIKE '192.168.%' AND [date] > 876693600
|
||||
|
||||
|
||||
|
||||
// IN array
|
||||
$array = array(1, 2, 3);
|
||||
dibi::test("
|
||||
SELECT *
|
||||
FROM [people]
|
||||
WHERE [id] IN (", $array, ")
|
||||
");
|
||||
// -> SELECT * FROM [people] WHERE [id] IN ( 1, 2, 3 )
|
||||
|
||||
|
||||
|
||||
// ORDER BY array
|
||||
$order = array(
|
||||
'field1' => 'asc',
|
||||
'field2' => 'desc',
|
||||
);
|
||||
dibi::test("
|
||||
SELECT *
|
||||
FROM [people]
|
||||
ORDER BY %by", $order, "
|
||||
");
|
||||
// -> SELECT * FROM [people] ORDER BY [field1] ASC, [field2] DESC
|
||||
|
58
examples/sql-condition.php
Normal file
58
examples/sql-condition.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<style>
|
||||
pre.dibi { padding-bottom: 10px; }
|
||||
</style>
|
||||
<h1>dibi conditional SQL example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
$cond1 = TRUE;
|
||||
$cond2 = FALSE;
|
||||
$foo = -1;
|
||||
$bar = 2;
|
||||
|
||||
|
||||
$name = $cond1 ? 'K%' : NULL;
|
||||
|
||||
// if & end
|
||||
dibi::test('
|
||||
SELECT *
|
||||
FROM [customers]
|
||||
%if', isset($name), 'WHERE [name] LIKE %s', $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]=%i", $foo, "
|
||||
%else %if", ($bar > 0), "AND [bar]=%i", $bar, "
|
||||
");
|
||||
// -> SELECT * FROM [people] WHERE [id] > 0 AND [bar]=2
|
||||
|
||||
|
||||
|
||||
// nested condition
|
||||
dibi::test('
|
||||
SELECT *
|
||||
FROM [customers]
|
||||
WHERE
|
||||
%if', isset($name), '[name] LIKE %s', $name, '
|
||||
%if', $cond2, 'AND [admin]=1 %end
|
||||
%else 1 LIMIT 10 %end'
|
||||
);
|
||||
// -> SELECT * FROM [customers] WHERE LIMIT 10
|
45
examples/table-prefix.php
Normal file
45
examples/table-prefix.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<h1>dibi prefix & substitute example</h1>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
|
||||
|
||||
// create new substitution :blog: ==> wp_
|
||||
dibi::addSubst('blog', 'wp_');
|
||||
|
||||
dibi::test("UPDATE [:blog:items] SET [text]='Hello World'");
|
||||
// -> UPDATE [wp_items] SET [text]='Hello World'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// create new substitution :: (empty) ==> my_
|
||||
dibi::addSubst('', 'my_');
|
||||
|
||||
dibi::test("UPDATE [database.::table] SET [text]='Hello World'");
|
||||
// -> UPDATE [database].[my_table] SET [text]='Hello World'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// create substitution fallback
|
||||
function substFallBack($expr)
|
||||
{
|
||||
return 'the_' . $expr;
|
||||
}
|
||||
|
||||
dibi::setSubstFallBack('substFallBack');
|
||||
|
||||
dibi::test("UPDATE [:account:user] SET [name]='John Doe'");
|
||||
// -> UPDATE [the_accountuser] SET [name]='John Doe'
|
30
examples/transaction.php
Normal file
30
examples/transaction.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<h1>dibi transaction example</h1>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
require_once 'Nette/Debug.php';
|
||||
require_once '../dibi/dibi.php';
|
||||
|
||||
|
||||
dibi::connect(array(
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'sample.sdb',
|
||||
));
|
||||
|
||||
|
||||
echo "<h2>Before:</h2>\n";
|
||||
dibi::query('SELECT * FROM [products]')->dump();
|
||||
// -> 3 rows
|
||||
|
||||
|
||||
dibi::begin();
|
||||
dibi::query('INSERT INTO [products]', array(
|
||||
'title' => 'Test product',
|
||||
));
|
||||
dibi::rollback(); // or dibi::commit();
|
||||
|
||||
|
||||
|
||||
echo "<h2>After:</h2>\n";
|
||||
dibi::query('SELECT * FROM [products]')->dump();
|
||||
// -> 3 rows
|
BIN
icons/dibi-powered.gif
Normal file
BIN
icons/dibi-powered.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 300 B |
16
icons/example.html
Normal file
16
icons/example.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<style>
|
||||
h1 {
|
||||
font-family: Trebuchet MS,"Geneva CE", lucida, sans-serif;
|
||||
color: #1e5eb6;
|
||||
}
|
||||
img {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<h1>Icon for your website</h1>
|
||||
|
||||
|
||||
<a href="http://dibiphp.com" title="dibi - tiny 'n' smart database abstraction layer"
|
||||
><img src="dibi-powered.gif" width="80" height="15" alt="dibi powered" /></a>
|
69
license.cs.txt
Normal file
69
license.cs.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
----------------------------------------------------------------------------------
|
||||
Tento text je NEOFICI<43>LN<4C>M p<>ekladem "Dibi license". Nevyjad<61>uje pr<70>vn<76> podstatu
|
||||
podm<EFBFBD>nek pro <20><><EFBFBD>en<65> tohoto softwaru - k tomuto <20><>elu slou<6F><75> v<>hradn<64> p<>vodn<64>
|
||||
anglick<EFBFBD> verze licence.
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Dibi Licence, verze 1
|
||||
======================
|
||||
|
||||
Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
V<EFBFBD>echna pr<70>va vyhrazena.
|
||||
|
||||
Tato licence je pr<70>vn<76> ujedn<64>n<EFBFBD> mezi v<>mi a Davidem Grudlem (d<>le Author)
|
||||
pro pot<6F>eby pou<6F>it<69> "dibi" (d<>le "Software"). Z<>sk<73>n<EFBFBD>m, pou<6F>it<69>m
|
||||
a/nebo zkop<6F>rov<6F>n<EFBFBD>m Software projevujete souhlas s t<>m, <20>e jste p<>e<EFBFBD>etli,
|
||||
porozum<EFBFBD>li a budete jednat v souladu s podm<64>nkami t<>to licence.
|
||||
|
||||
|
||||
POVOLEN<EFBFBD> POU<4F>IT<49>
|
||||
----------------
|
||||
|
||||
Je povoleno pou<6F><75>vat, kop<6F>rovat, modifikovat a distribuovat Software
|
||||
a jeho dokumentaci, v p<>vodn<64>m i upravovan<61>m tvaru, pro jak<61>koliv <20><>el,
|
||||
za p<>edpokladu, <20>e jsou spln<6C>ny tyto podm<64>nky:
|
||||
|
||||
1. Kopie t<>to licen<65>n<EFBFBD> smlouvy mus<75> b<>t sou<6F><75>st<73> distribuce.
|
||||
|
||||
2. <20><><EFBFBD>en<65> zdrojov<6F> k<>d mus<75> zachovat v<><76>e uvedenou informaci o autorsk<73>ch
|
||||
pr<70>vech ve v<>ech souborech zdrojov<6F>ho k<>du.
|
||||
|
||||
3. <20><><EFBFBD>en<65> bin<69>rn<72> tvar mus<75> reprodukovat v<><76>e uvedenou informaci o autorsk<73>ch
|
||||
pr<70>vech v dokumentaci a/nebo jin<69>ch materi<72>lech poskytovan<61>ch s distribuc<75>.
|
||||
|
||||
4. Produkty odvozen<65> od Software mus<75> obsahovat potvrzen<65>, <20>e jsou odvozen<65>
|
||||
od "dibi", ve sv<73> dokumentaci a/nebo jin<69>ch materi<72>lech
|
||||
poskytovan<61>ch s distribuc<75>.
|
||||
|
||||
5. N<>zev "dibi" nesm<73> b<>t pou<6F>it p<>i podpo<70>e nebo propagaci produkt<6B>
|
||||
odvozen<65>mi ze Software bez p<>edchoz<6F>ho p<>semn<6D>ho souhlasu Autora.
|
||||
|
||||
6. Produkty odvozen<65> od Software nesm<73> b<>t nazv<7A>ny "dibi",
|
||||
ani se nesm<73> "dibi" objevit v jejich n<>zvu bez p<>edchoz<6F>ho
|
||||
p<>semn<6D>ho souhlasu Autora.
|
||||
|
||||
|
||||
ZBAVEN<EFBFBD> ZODPOV<4F>DNOSTI
|
||||
---------------------
|
||||
|
||||
Souhlas<EFBFBD>te se zbaven<65>m zodpov<6F>dnosti a kryt<79>m Autora a p<>isp<73>vatel<65> v<><76>i
|
||||
jak<EFBFBD>mkoliv p<><70>m<EFBFBD>m, nep<65><70>m<EFBFBD>m, n<>hodn<64>m nebo n<>sledn<64>m odjinud poch<63>zej<65>c<EFBFBD>m <20>kod<6F>m,
|
||||
<EFBFBD>alob<EFBFBD>m nebo spor<6F>m, jako<6B> i p<>ed v<>emi souvisej<65>c<EFBFBD>mi n<>klady, z<>vazky,
|
||||
od<EFBFBD>kodn<EFBFBD>n<EFBFBD>mi, <20>hradami nebo poplatky vypl<70>vaj<61>c<EFBFBD>ch z pou<6F><75>v<EFBFBD>n<EFBFBD> nebo
|
||||
nespr<EFBFBD>vn<EFBFBD>ho u<>it<69> Software, nebo z poru<72>en<65> podm<64>nek t<>to licence.
|
||||
|
||||
|
||||
Z<EFBFBD>RUKA SE NEPOSKYTUJE
|
||||
---------------------
|
||||
|
||||
TENTO SOFTWARE JE POSKYTOV<4F>N DR<44>ITELEM LICENCE A JEHO P<>ISP<53>VATELI "JAK STOJ<4F> A LE<4C><45>"
|
||||
A JAK<41>KOLIV V<>SLOVN<56> NEBO P<>EDPOKL<4B>DAN<41> Z<>RUKY V<>ETN<54>, ALE NEJEN, P<>EDPOKL<4B>DAN<41>CH
|
||||
OBCHODN<EFBFBD>CH Z<>RUK A Z<>RUKY VHODNOSTI PRO JAK<41>KOLIV <20><>EL JSOU POP<4F>ENY.
|
||||
DR<EFBFBD>ITEL, ANI P<>ISP<53>VATEL<45> NEBUDOU V <20><>DN<44>M P<><50>PAD<41> ODPOV<4F>DNI ZA JAK<41>KOLIV P<><50>M<EFBFBD>,
|
||||
NEP<EFBFBD><EFBFBD>M<EFBFBD>, N<>HODN<44>, ZVL<56><4C>TN<54>, P<><50>KLADN<44> NEBO VYPL<50>VAJ<41>C<EFBFBD> <20>KODY (V<>ETN<54>, ALE NEJEN,
|
||||
<EFBFBD>KOD VZNIKL<4B>CH NARU<52>EN<45>M DOD<4F>VEK ZBO<42><4F> NEBO SLU<4C>EB; ZTR<54>TOU POU<4F>ITELNOSTI,
|
||||
DAT NEBO ZISK<53>; NEBO P<>ERU<52>EN<45>M OBCHODN<44> <20>INNOSTI) JAKKOLIV ZP<5A>SOBEN<45> NA Z<>KLAD<41>
|
||||
JAK<EFBFBD>KOLIV TEORIE O ZODPOV<4F>DNOSTI, A<> U<> PLYNOUC<55> Z JIN<49>HO SMLUVN<56>HO VZTAHU,
|
||||
UR<EFBFBD>IT<EFBFBD> ZODPOV<4F>DNOSTI NEBO P<>E<EFBFBD>INU (V<>ETN<54> NEDBALOSTI) NA JAK<41>MKOLIV ZP<5A>SOBU POU<4F>IT<49>
|
||||
TOHOTO SOFTWARE, I V P<><50>PAD<41>, <20>E DR<44>ITEL PR<50>V BYL UPOZORN<52>N NA MO<4D>NOST TAKOV<4F>CH <20>KOD.
|
62
license.txt
Normal file
62
license.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
The Dibi License, Version 1
|
||||
============================
|
||||
|
||||
Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
This license is a legal agreement between you and David Grudl (the "Author")
|
||||
for the use of "dibi" (the "Software"). By obtaining, using and/or
|
||||
copying the Software, you agree that you have read, understood, and will
|
||||
comply with the terms and conditions of this license.
|
||||
|
||||
|
||||
PERMITTED USE
|
||||
-------------
|
||||
|
||||
You are permitted to use, copy, modify, and distribute the Software and its
|
||||
documentation, with or without modification, for any purpose, provided that
|
||||
the following conditions are met:
|
||||
|
||||
1. A copy of this license agreement must be included with the distribution.
|
||||
|
||||
2. Redistributions of source code must retain the above copyright notice in
|
||||
all source code files.
|
||||
|
||||
3. Redistributions in binary form must reproduce the above copyright notice
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
4. Products derived from the Software must include an acknowledgment that
|
||||
they are derived from "dibi" in their documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
5. The name "dibi" must not be used to endorse or promote products
|
||||
derived from the Software without prior written permission from Author.
|
||||
|
||||
6. Products derived from the Software may not be called "dibi",
|
||||
nor may "dibi" appear in their name, without prior written
|
||||
permission from Author.
|
||||
|
||||
|
||||
INDEMNITY
|
||||
---------
|
||||
|
||||
You agree to indemnify and hold harmless the Author and any contributors
|
||||
for any direct, indirect, incidental, or consequential third-party claims,
|
||||
actions or suits, as well as any related expenses, liabilities, damages,
|
||||
settlements or fees arising from your use or misuse of the Software,
|
||||
or a violation of any terms of this license.
|
||||
|
||||
|
||||
DISCLAIMER OF WARRANTY
|
||||
----------------------
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "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 HOLDER 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.
|
@@ -1,271 +0,0 @@
|
||||
----------------------------------------------------------------------------------
|
||||
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
|
||||
----------------------------------------------------------------------------------
|
@@ -1,279 +0,0 @@
|
||||
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
|
41
readme.txt
Normal file
41
readme.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
Dibi (c) David Grudl, 2005-2008 (http://davidgrudl.com)
|
||||
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Thank you for downloading Dibi!
|
||||
|
||||
Database access functions in PHP are not standardised. This is class library
|
||||
to hide the differences between the different databases access.
|
||||
|
||||
The files in this archive are released under the Dibi license.
|
||||
See license.txt in this directory for a copy of the license.
|
||||
|
||||
|
||||
|
||||
Documentation and Examples
|
||||
--------------------------
|
||||
|
||||
Refer to the 'examples' directory for examples. Dibi documentation is
|
||||
available on the homepage:
|
||||
|
||||
http://dibiphp.com
|
||||
|
||||
|
||||
|
||||
Dibi.compact
|
||||
------------
|
||||
|
||||
This is shrinked single-file version of whole Dibi, useful when you don't
|
||||
want to modify library, but just use it.
|
||||
|
||||
This is exactly the same as normal version, just only comments and
|
||||
whitespaces are removed.
|
||||
|
||||
|
||||
|
||||
-----
|
||||
For more information, visit the author's weblog (in czech language):
|
||||
http://phpfashion.com
|
1
version.txt
Normal file
1
version.txt
Normal file
@@ -0,0 +1 @@
|
||||
Dibi 1.0 (revision $WCREV$ released on $WCDATE$)
|
Reference in New Issue
Block a user