Viewing file: dibi.compact.php (84.37 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php //netteloader=IDibiVariable,IDataSource,IDibiProfiler,IDibiDriver,DibiObject,DibiException,DibiDriverException,DibiConnection,DibiResult,DibiResultIterator,DibiRow,DibiTranslator,DibiVariable,DibiDataSource,DibiFluent,DibiDatabaseInfo,DibiTableInfo,DibiColumnInfo,DibiForeignKeyInfo,DibiIndexInfo,DibiProfiler,dibi,DibiMySqlDriver,DibiMySqliDriver,DibiOdbcDriver,DibiPdoDriver,DibiPostgreDriver,DibiSqliteDriver
/** * dibi - tiny'n'smart database abstraction layer * ---------------------------------------------- * * Copyright (c) 2005, 2009 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, 2009 David Grudl * @license http://dibiphp.com/license dibi license * @link http://dibiphp.com * @package dibi * @version 1.01 (revision 209 released on 2009/03/19 13:18:16) */
if(version_compare(PHP_VERSION,'5.1.0','<')){throw new Exception('dibi needs PHP 5.1.0 or newer.');}if(!class_exists('NotImplementedException',FALSE)){class NotImplementedException extends LogicException{}}if(!class_exists('NotSupportedException',FALSE)){class NotSupportedException extends LogicException{}}if(!class_exists('MemberAccessException',FALSE)){class MemberAccessException extends LogicException{}}if(!class_exists('InvalidStateException',FALSE)){class InvalidStateException extends RuntimeException{}}if(!class_exists('IOException',FALSE)){class IOException extends RuntimeException{}}if(!class_exists('FileNotFoundException',FALSE)){class FileNotFoundException extends IOException{}}if(!interface_exists('IDebuggable',FALSE)){interface IDebuggable{function getPanels();}}interface IDibiVariable{function toSql(DibiTranslator$translator,$modifier);}interface IDataSource extends Countable,IteratorAggregate{}interface IDibiProfiler{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;function before(DibiConnection$connection,$event,$sql=NULL);function after($ticket,$result=NULL);function exception(DibiDriverException$exception);}interface IDibiDriver{function connect(array&$config);function disconnect();function query($sql);function getAffectedRows();function getInsertId($sequence);function begin($savepoint=NULL);function commit($savepoint=NULL);function rollback($savepoint=NULL);function getResource();function escape($value,$type);function unescape($value,$type);function applyLimit(&$sql,$limit,$offset);function getRowCount();function seek($row);function fetch($type);function free();function getColumnsMeta();function getResultResource();function getTables();function getColumns($table);function getIndexes($table);function getForeignKeys($table);}abstract class DibiObject{private static$extMethods;final public function getClass(){return get_class($this);}final public function getReflection(){return new ReflectionObject($this);}public function __call($name,$args){$class=get_class($this);if($name===''){throw new MemberAccessException("Call to class '$class' method without name.");}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;}}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().");}public static function __callStatic($name,$args){$class=get_called_class();throw new MemberAccessException("Call to undefined static method $class::$name().");}public static function extensionMethod($name,$callback=NULL){if(self::$extMethods===NULL||$name===NULL){$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,':');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){$l[$class]=$callback;$l['']=NULL;return NULL;}if(empty($l)){return FALSE;}elseif(isset($l[''][$class])){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;}public function&__get($name){$class=get_class($this);if($name===''){throw new MemberAccessException("Cannot read a class '$class' property without name.");}$name[0]=$name[0]&"\xDF";$m='get'.$name;if(self::hasAccessor($class,$m)){$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.");}public function __set($name,$value){$class=get_class($this);if($name===''){throw new MemberAccessException("Cannot assign to a class '$class' property without name.");}$name[0]=$name[0]&"\xDF";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.");}public function __isset($name){$name[0]=$name[0]&"\xDF";return$name!==''&&self::hasAccessor(get_class($this),'get'.$name);}public function __unset($name){$class=get_class($this);throw new MemberAccessException("Cannot unset the property $class::\$$name.");}private static function hasAccessor($c,$m){static$cache;if(!isset($cache[$c])){$cache[$c]=array_flip(get_class_methods($c));}return isset($cache[$c][$m]);}}class DibiException extends Exception implements IDebuggable{private$sql;public function __construct($message=NULL,$code=0,$sql=NULL){parent::__construct($message,(int)$code);$this->sql=$sql;}final public function getSql(){return$this->sql;}public function __toString(){return parent::__toString().($this->sql?"\nSQL: ".$this->sql:'');}public function getPanels(){$panels=array();if($this->sql!==NULL){$panels['SQL']=array('expanded'=>TRUE,'content'=>dibi::dump($this->sql,TRUE));}return$panels;}}class DibiDriverException extends DibiException{private static$errorMsg;public static function tryError(){set_error_handler(array(__CLASS__,'_errorHandler'),E_ALL);self::$errorMsg=NULL;}public static function catchError(&$message){restore_error_handler();$message=self::$errorMsg;self::$errorMsg=NULL;return$message!==NULL;}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;}}class DibiConnection extends DibiObject{private$config;private$driver;private$profiler;private$connected=FALSE;private$inTxn=FALSE;public function __construct($config,$name=NULL){if(class_exists('Debug',FALSE)){Debug::addColophon(array('dibi','getColophon'));}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['substitutes'])){foreach($config['substitutes']as$key=>$value){dibi::addSubst($key,$value);}}if(empty($config['lazy'])){$this->connect();}}public function __destruct(){$this->disconnect();}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);}}}final public function disconnect(){if($this->connected){if($this->inTxn){$this->rollback();}$this->driver->disconnect();$this->connected=FALSE;}}final public function isConnected(){return$this->connected;}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;}}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;}}final public function getDriver(){return$this->driver;}final public function getResource(){trigger_error('Deprecated: use getDriver()->getResource(...) instead.',E_USER_WARNING);return$this->driver->getResource();}final public function query($args){$args=func_get_args();$this->connect();$translator=new DibiTranslator($this->driver);return$this->nativeQuery($translator->translate($args));}final public function sql($args){$args=func_get_args();$this->connect();$translator=new DibiTranslator($this->driver);return$translator->translate($args);}final public function test($args){$args=func_get_args();$this->connect();try{$translator=new DibiTranslator($this->driver);dibi::dump($translator->translate($args));return TRUE;}catch(DibiException$e){dibi::dump($e->getSql());return FALSE;}}final public function dataSource($args){$args=func_get_args();$this->connect();$translator=new DibiTranslator($this->driver);return new DibiDataSource($translator->translate($args),$this);}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);}dibi::$numOfQueries++;dibi::$sql=$sql;dibi::$elapsedTime=FALSE;$time=-microtime(TRUE);if($res=$this->driver->query($sql)){$res=new DibiResult($res,$this->config);}else{$res=$this->driver->getAffectedRows();}$time+=microtime(TRUE);dibi::$elapsedTime=$time;dibi::$totalTime+=$time;if(isset($ticket)){$this->profiler->after($ticket,$res);}return$res;}public function getAffectedRows(){$rows=$this->driver->getAffectedRows();if(!is_int($rows)||$rows<0)throw new DibiException('Cannot retrieve number of affected rows.');return$rows;}public function affectedRows(){return$this->getAffectedRows();}public function getInsertId($sequence=NULL){$id=$this->driver->getInsertId($sequence);if($id<1)throw new DibiException('Cannot retrieve last generated ID.');return(int)$id;}public function insertId($sequence=NULL){return$this->getInsertId($sequence);}public function begin($savepoint=NULL){$this->connect();if(!$savepoint&&$this->inTxn){throw new DibiException('There is already an active transaction.');}if($this->profiler!==NULL){$ticket=$this->profiler->before($this,IDibiProfiler::BEGIN,$savepoint);}if($savepoint&&!$this->inTxn){$this->driver->begin();}$this->driver->begin($savepoint);$this->inTxn=TRUE;if(isset($ticket)){$this->profiler->after($ticket);}}public function commit($savepoint=NULL){if(!$this->inTxn){throw new DibiException('There is no active transaction.');}if($this->profiler!==NULL){$ticket=$this->profiler->before($this,IDibiProfiler::COMMIT,$savepoint);}$this->driver->commit($savepoint);$this->inTxn=(bool)$savepoint;if(isset($ticket)){$this->profiler->after($ticket);}}public function rollback($savepoint=NULL){if(!$this->inTxn){throw new DibiException('There is no active transaction.');}if($this->profiler!==NULL){$ticket=$this->profiler->before($this,IDibiProfiler::ROLLBACK,$savepoint);}$this->driver->rollback($savepoint);$this->inTxn=(bool)$savepoint;if(isset($ticket)){$this->profiler->after($ticket);}}public function inTransaction(){return$this->inTxn;}public function escape($value,$type=dibi::TEXT){trigger_error('Deprecated: use getDriver()->escape(...) instead.',E_USER_WARNING);$this->connect();return$this->driver->escape($value,$type);}public function unescape($value,$type=dibi::BINARY){trigger_error('Deprecated: use getDriver()->unescape(...) instead.',E_USER_WARNING);return$this->driver->unescape($value,$type);}public function delimite($value){trigger_error('Deprecated: use getDriver()->escape(...) instead.',E_USER_WARNING);return$this->driver->escape($value,dibi::IDENTIFIER);}public function applyLimit(&$sql,$limit,$offset){trigger_error('Deprecated: use getDriver()->applyLimit(...) instead.',E_USER_WARNING);$this->driver->applyLimit($sql,$limit,$offset);}public function command(){return new DibiFluent($this);}public function select($args){$args=func_get_args();return$this->command()->__call('select',$args);}public function update($table,array$args){return$this->command()->update('%n',$table)->set($args);}public function insert($table,array$args){return$this->command()->insert()->into('%n',$table,'(%n)',array_keys($args))->values('%l',array_values($args));}public function delete($table){return$this->command()->delete()->from('%n',$table);}public function setProfiler(IDibiProfiler$profiler=NULL){$this->profiler=$profiler;}public function getProfiler(){return$this->profiler;}public function fetch($args){$args=func_get_args();return$this->query($args)->fetch();}public function fetchAll($args){$args=func_get_args();return$this->query($args)->fetchAll();}public function fetchSingle($args){$args=func_get_args();return$this->query($args)->fetchSingle();}public function fetchPairs($args){$args=func_get_args();return$this->query($args)->fetchPairs();}public function loadFile($file){$this->connect();@set_time_limit(0);$handle=@fopen($file,'r');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;}public function getDatabaseInfo(){$this->connect();return new DibiDatabaseInfo($this->driver,isset($this->config['database'])?$this->config['database']:NULL);}public function __wakeup(){throw new NotSupportedException('You cannot serialize or unserialize '.$this->getClass().' instances.');}public function __sleep(){throw new NotSupportedException('You cannot serialize or unserialize '.$this->getClass().' instances.');}}class DibiResult extends DibiObject implements IDataSource{private$driver;private$xlat;private$meta;private$fetched=FALSE;private$withTables=FALSE;private$class='DibiRow';public function __construct($driver,$config){$this->driver=$driver;if(!empty($config[dibi::RESULT_WITH_TABLES])){$this->setWithTables(TRUE);}}public function __destruct(){@$this->free();}final public function getResource(){return$this->getDriver()->getResultResource();}final public function seek($row){return($row!==0||$this->fetched)?(bool)$this->getDriver()->seek($row):TRUE;}final public function getRowCount(){return$this->getDriver()->getRowCount();}final public function rowCount(){return$this->getDriver()->getRowCount();}final public function free(){if($this->driver!==NULL){$this->driver->free();$this->driver=NULL;}}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;}}final public function getWithTables(){return(bool)$this->withTables;}public function setRowClass($class){$this->class=$class;}public function getRowClass(){return$this->class;}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;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$this->class($row);}final public function fetchSingle(){$row=$this->getDriver()->fetch(TRUE);if(!is_array($row))return FALSE;$this->fetched=TRUE;$value=reset($row);$key=key($row);if(isset($this->xlat[$key])){$type=$this->xlat[$key];return$this->convert($value,$type['type'],$type['format']);}return$value;}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();$data=array();do{if($limit===0)break;$limit--;$data[]=$row;}while($row=$this->fetch());return$data;}final public function fetchAssoc($assoc){$this->seek(0);$row=$this->fetch();if(!$row)return array();$data=NULL;$assoc=explode(',',$assoc);foreach($assoc as$as){if($as!=='#'&&$as!=='='&&$as!=='@'&&!isset($row[$as])){throw new InvalidArgumentException("Unknown column '$as' in associative descriptor.");}}$leaf='@';$last=count($assoc)-1;while($assoc[$last]==='='||$assoc[$last]==='@'){$leaf=$assoc[$last];unset($assoc[$last]);$last--;if($last<0){$assoc[]='#';break;}}do{$arr=(array)$row;$x=&$data;foreach($assoc as$i=>$as){if($as==='#'){$x=&$x[];}elseif($as==='='){if($x===NULL){$x=$arr;$x=&$x[$assoc[$i+1]];$x=NULL;}else{$x=&$x[$assoc[$i+1]];}}elseif($as==='@'){if($x===NULL){$x=clone$row;$x=&$x->{$assoc[$i+1]};$x=NULL;}else{$x=&$x->{$assoc[$i+1]};}}else{$x=&$x[$arr[$as]];}}if($x===NULL){if($leaf==='='){$x=$arr;}else{$x=$row;}}}while($row=$this->fetch());unset($x);return$data;}final public function fetchPairs($key=NULL,$value=NULL){$this->seek(0);$row=$this->fetch();if(!$row)return array();$data=array();if($value===NULL){if($key!==NULL){throw new InvalidArgumentException("Either none or both columns must be specified.");}$tmp=array_keys((array)$row);$key=$tmp[0];if(count($row)<2){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){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;}final public function setType($col,$type,$format=NULL){$this->xlat[$col]=array('type'=>$type,'format'=>$format);}final public function detectTypes(){foreach($this->getMeta()as$info){$this->xlat[$info['name']]=array('type'=>$info['type'],'format'=>NULL);}}final public function setTypes(array$types){$this->xlat=$types;}final public function getType($col){return isset($this->xlat[$col])?$this->xlat[$col]:NULL;}final public function convert($value,$type,$format=NULL){if($value===NULL||$value===FALSE){return$value;}switch($type){case dibi::TEXT:return(string)$value;case dibi::BINARY:return$this->getDriver()->unescape($value,$type);case dibi::INTEGER:return(int)$value;case dibi::FLOAT:return(float)$value;case dibi::DATE:case dibi::DATETIME:$value=is_numeric($value)?(int)$value:strtotime($value);return$format===NULL?$value:date($format,$value);case dibi::BOOL:return((bool)$value)&&$value!=='f'&&$value!=='F';default:return$value;}}final public function getColumns(){$cols=array();foreach($this->getMeta()as$info){$cols[]=new DibiColumnInfo($this->getDriver(),$info);}return$cols;}public function getColumnNames($withTables=FALSE){$cols=array();foreach($this->getMeta()as$info){$cols[]=$info[$withTables?'fullname':'name'];}return$cols;}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){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";}}final public function getIterator($offset=NULL,$limit=NULL){return new DibiResultIterator($this,$offset,$limit);}final public function count(){return$this->getRowCount();}private function getDriver(){if($this->driver===NULL){throw new InvalidStateException('Result-set was released from memory.');}return$this->driver;}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;}}class DibiResultIterator implements Iterator{private$result;private$offset;private$limit;private$row;private$pointer;public function __construct(DibiResult$result,$offset=NULL,$limit=NULL){$this->result=$result;$this->offset=(int)$offset;$this->limit=$limit===NULL?-1:(int)$limit;}public function rewind(){$this->pointer=0;$this->result->seek($this->offset);$this->row=$this->result->fetch();}public function key(){return$this->pointer;}public function current(){return$this->row;}public function next(){$this->row=$this->result->fetch();$this->pointer++;}public function valid(){return!empty($this->row)&&($this->limit<0||$this->pointer<$this->limit);}}class DibiRow extends ArrayObject{public function __construct($arr){parent::__construct($arr,2);}public function __wakeup(){$this->setFlags(2);}}final class DibiTranslator extends DibiObject{private$driver;private$cursor;private$args;private$hasError;private$comment;private$ifLevel;private$ifLevelStart;private$limit;private$offset;public function __construct(IDibiDriver$driver){$this->driver=$driver;}public function getDriver(){return$this->driver;}public function translate(array$args){$this->limit=-1;$this->offset=0;$this->hasError=FALSE;$commandIns=NULL;$lastArr=NULL;$cursor=&$this->cursor;$cursor=0;$this->args=array_values($args);$args=&$this->args;$this->ifLevel=$this->ifLevelStart=0;$comment=&$this->comment;$comment=FALSE;$sql=array();while($cursor<count($args)){$arg=$args[$cursor];$cursor++;if(is_string($arg)){$toSkip=strcspn($arg,'`[\'":%');if(strlen($arg)===$toSkip){$sql[]=$arg;}else{$sql[]=substr($arg,0,$toSkip).preg_replace_callback('/(?=[`[\'":%])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?)|%([a-zA-Z]{1,4})(?![a-zA-Z]))/s',array($this,'cb'),substr($arg,$toSkip));}continue;}if($comment){$sql[]='...';continue;}if($arg instanceof ArrayObject){$arg=(array)$arg;}if(is_array($arg)){if(is_string(key($arg))){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){$cursor=0;array_splice($args,0,1,$arg);continue;}}$sql[]=$this->formatValue($arg,FALSE);}if($comment)$sql[]="*/";$sql=implode(' ',$sql);if($this->hasError){throw new DibiException('SQL translate error',0,$sql);}if($this->limit>-1||$this->offset>0){$this->driver->applyLimit($sql,$this->limit,$this->offset);}return$sql;}public function formatValue($value,$modifier){if($value instanceof ArrayObject){$value=(array)$value;}if(is_array($value)){$vx=$kx=array();switch($modifier){case'and':case'or':if(empty($value)){return$this->driver->escape(TRUE,'b');}foreach($value as$k=>$v){if(is_string($k)){$pair=explode('%',$k,2);$k=$this->delimite($pair[0]).' ';if(!isset($pair[1])){$v=$this->formatValue($v,FALSE);$vx[]=$k.($v==='NULL'?'IS ':'= ').$v;}elseif($pair[1]==='ex'){$vx[]=$k.$this->formatValue($v,'ex');}else{$v=$this->formatValue($v,$pair[1]);$vx[]=$k.($pair[1]==='l'?'IN ':($v==='NULL'?'IS ':'= ')).$v;}}else{$vx[]=$this->formatValue($v,'ex');}}return implode(' '.strtoupper($modifier).' ',$vx);case'n':foreach($value as$k=>$v){if(is_string($k)){$vx[]=$this->delimite($k).(empty($v)?'':' AS '.$v);}else{$vx[]=$this->delimite($v);}}return implode(', ',$vx);case'a':foreach($value as$k=>$v){$pair=explode('%',$k,2);$vx[]=$this->delimite($pair[0]).'='.$this->formatValue($v,isset($pair[1])?$pair[1]:FALSE);}return implode(', ',$vx);case'l':foreach($value as$k=>$v){$pair=explode('%',$k,2);$vx[]=$this->formatValue($v,isset($pair[1])?$pair[1]:FALSE);}return'('.implode(', ',$vx).')';case'v':foreach($value as$k=>$v){$pair=explode('%',$k,2);$kx[]=$this->delimite($pair[0]);$vx[]=$this->formatValue($v,isset($pair[1])?$pair[1]:FALSE);}return'('.implode(', ',$kx).') VALUES ('.implode(', ',$vx).')';case'by':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);case'ex':case'sql':$translator=new self($this->driver);return$translator->translate($value);default:foreach($value as$v){$vx[]=$this->formatValue($v,$modifier);}return implode(', ',$vx);}}if($modifier){if($value instanceof IDibiVariable){return$value->toSql($this,$modifier);}elseif($value instanceof DateTime){$value=$value->format('U');}elseif($value!==NULL&&!is_scalar($value)){$this->hasError=TRUE;return'**Unexpected type '.gettype($value).'**';}switch($modifier){case's':case'bin':case'b':return$value===NULL?'NULL':$this->driver->escape($value,$modifier);case'sn':return$value==''?'NULL':$this->driver->escape($value,dibi::TEXT);case'i':case'u':if(is_string($value)&&preg_match('#[+-]?\d+(e\d+)?$#A',$value)){return$value;}else{return$value===NULL?'NULL':(string)(int)($value+0);}case'f':if(is_string($value)&&is_numeric($value)&&strpos($value,'x')===FALSE){return$value;}else{return$value===NULL?'NULL':rtrim(rtrim(number_format($value,5,'.',''),'0'),'.');}case'd':case't':if($value===NULL){return'NULL';}else{return$this->driver->escape(is_numeric($value)?(int)$value:strtotime($value),$modifier);}case'by':case'n':return$this->delimite($value);case'ex':case'sql':$value=(string)$value;$toSkip=strcspn($value,'`[\'":');if(strlen($value)===$toSkip){return$value;}else{return substr($value,0,$toSkip).preg_replace_callback('/(?=[`[\'":])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?))/s',array($this,'cb'),substr($value,$toSkip));}case'SQL':return(string)$value;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**";}}if(is_string($value))return$this->driver->escape($value,dibi::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::BOOL);if($value===NULL)return'NULL';if($value instanceof IDibiVariable)return$value->toSql($this,NULL);$this->hasError=TRUE;return'**Unexpected '.gettype($value).'**';}private function cb($matches){if(!empty($matches[10])){$mod=$matches[10];$cursor=&$this->cursor;if($cursor>=count($this->args)&&$mod!=='else'&&$mod!=='end'){$this->hasError=TRUE;return"**Extra modifier %$mod**";}if($mod==='if'){$this->ifLevel++;$cursor++;if(!$this->comment&&!$this->args[$cursor-1]){$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){$this->ifLevelStart=0;$this->comment=FALSE;return"*/";}return'';}elseif($mod==='ex'){array_splice($this->args,$cursor,1,$this->args[$cursor]);return'';}elseif($mod==='lmt'){if($this->args[$cursor]!==NULL)$this->limit=(int)$this->args[$cursor];$cursor++;return'';}elseif($mod==='ofs'){if($this->args[$cursor]!==NULL)$this->offset=(int)$this->args[$cursor];$cursor++;return'';}else{$cursor++;return$this->formatValue($this->args[$cursor-1],$mod);}}if($this->comment)return'...';if($matches[1])return$this->delimite($matches[1]);if($matches[2])return$this->delimite($matches[2]);if($matches[3])return$this->driver->escape(str_replace("''","'",$matches[4]),dibi::TEXT);if($matches[5])return$this->driver->escape(str_replace('""','"',$matches[6]),dibi::TEXT);if($matches[7]){$this->hasError=TRUE;return'**Alone quote**';}if($matches[8]){$m=substr($matches[8],0,-1);$m=isset(dibi::$substs[$m])?dibi::$substs[$m]:call_user_func(dibi::$substFallBack,$m);return$matches[9]==''?$this->formatValue($m,FALSE):$m.$matches[9];}die('this should be never executed');}private function delimite($value){if($value==='*'){return'*';}elseif(strpos($value,':')!==FALSE){$value=preg_replace_callback('#:(.*):#U',array(__CLASS__,'subCb'),$value);}return$this->driver->escape($value,dibi::IDENTIFIER);}private static function subCb($m){$m=$m[1];return isset(dibi::$substs[$m])?dibi::$substs[$m]:call_user_func(dibi::$substFallBack,$m);}}class DibiVariable extends DibiObject implements IDibiVariable{public$value;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);}}class DibiDataSource extends DibiObject implements IDataSource{private$connection;private$sql;private$result;private$count;private$totalCount;private$cols=array();private$sorting=array();private$conds=array();private$offset;private$limit;public function __construct($sql,DibiConnection$connection){if(strpos($sql,' ')===FALSE){$this->sql=$sql;}else{$this->sql='('.$sql.') AS t';}$this->connection=$connection;}public function select($col,$as=NULL){if(is_array($col)){$this->cols=$col;}else{$this->cols[$col]=$as;}$this->result=NULL;return$this;}public function where($cond){if(is_array($cond)){$this->conds[]=$cond;}else{$this->conds[]=func_get_args();}$this->result=$this->count=NULL;return$this;}public function orderBy($row,$sorting='ASC'){if(is_array($row)){$this->sorting=$row;}else{$this->sorting[$row]=$sorting;}$this->result=NULL;return$this;}public function applyLimit($limit,$offset=NULL){$this->limit=$limit;$this->offset=$offset;$this->result=$this->count=NULL;return$this;}final public function getConnection(){return$this->connection;}public function getResult(){if($this->result===NULL){$this->result=$this->connection->nativeQuery($this->__toString());}return$this->result;}public function getIterator(){return$this->getResult()->getIterator();}public function fetch(){return$this->getResult()->fetch();}public function fetchSingle(){return$this->getResult()->fetchSingle();}public function fetchAll(){return$this->getResult()->fetchAll();}public function fetchAssoc($assoc){return$this->getResult()->fetchAssoc($assoc);}public function fetchPairs($key=NULL,$value=NULL){return$this->getResult()->fetchPairs($key,$value);}public function release(){$this->result=$this->count=NULL;}public function toFluent(){return$this->connection->select('*')->from('(%SQL) AS t',$this->__toString());}public function toDataSource(){return new self($this->__toString(),$this->connection);}final public function __toString(){return$this->connection->sql(' SELECT %n',(empty($this->cols)?'*':$this->cols),' FROM %SQL',$this->sql,' %ex',$this->conds?array('WHERE %and',$this->conds):NULL,' %ex',$this->sorting?array('ORDER BY %by',$this->sorting):NULL,' %ofs %lmt',$this->offset,$this->limit);}public function count(){if($this->count===NULL){$this->count=$this->conds||$this->offset||$this->limit?(int)$this->connection->nativeQuery('SELECT COUNT(*) FROM ('.$this->__toString().') AS t')->fetchSingle():$this->getTotalCount();}return$this->count;}public function getTotalCount(){if($this->totalCount===NULL){$this->totalCount=(int)$this->connection->nativeQuery('SELECT COUNT(*) FROM '.$this->sql)->fetchSingle();}return$this->totalCount;}}class DibiFluent extends DibiObject implements IDataSource{public static$masks=array('SELECT'=>array('SELECT','DISTINCT','FROM','WHERE','GROUP BY','HAVING','ORDER BY','LIMIT','OFFSET'),'UPDATE'=>array('UPDATE','SET','WHERE','ORDER BY','LIMIT'),'INSERT'=>array('INSERT','INTO','VALUES','SELECT'),'DELETE'=>array('DELETE','FROM','USING','WHERE','ORDER BY','LIMIT'));public static$modifiers=array('SELECT'=>'%n','FROM'=>'%n','IN'=>'%l','VALUES'=>'%l','SET'=>'%a','WHERE'=>'%and','HAVING'=>'%and','ORDER BY'=>'%by','GROUP BY'=>'%by');public static$separators=array('SELECT'=>',','FROM'=>FALSE,'WHERE'=>'AND','GROUP BY'=>',','HAVING'=>'AND','ORDER BY'=>',','LIMIT'=>FALSE,'OFFSET'=>FALSE,'SET'=>',','VALUES'=>',','INTO'=>FALSE);private$connection;private$command;private$clauses=array();private$flags=array();private$cursor;public function __construct(DibiConnection$connection){$this->connection=$connection;}public function __call($clause,$args){$clause=self::_formatClause($clause);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;}if(count($args)===1){$arg=$args[0];if($arg===TRUE){$args=array();}elseif(is_string($arg)&&preg_match('#^[a-z:_][a-z0-9_.:]*$#i',$arg)){$args=array('%n',$arg);}elseif($arg instanceof self){$args=array_merge(array('('),$arg->_export(),array(')'));}elseif(is_array($arg)){if(isset(self::$modifiers[$clause])){$args=array(self::$modifiers[$clause],$arg);}elseif(is_string(key($arg))){$args=array('%a',$arg);}}}if(array_key_exists($clause,$this->clauses)){$this->cursor=&$this->clauses[$clause];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{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;}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;}public function setFlag($flag,$value=TRUE){$flag=strtoupper($flag);if($value){$this->flags[$flag]=TRUE;}else{unset($this->flags[$flag]);}return$this;}final public function getFlag($flag){return isset($this->flags[strtoupper($flag)]);}final public function getCommand(){return$this->command;}final public function getConnection(){return$this->connection;}public function execute($return=NULL){$res=$this->connection->query($this->_export());return$return===dibi::IDENTIFIER?$this->connection->getInsertId():$res;}public function fetch(){if($this->command==='SELECT'){return$this->connection->query($this->_export(NULL,array('%lmt',1)))->fetch();}else{return$this->connection->query($this->_export())->fetch();}}public function fetchSingle(){if($this->command==='SELECT'){return$this->connection->query($this->_export(NULL,array('%lmt',1)))->fetchSingle();}else{return$this->connection->query($this->_export())->fetchSingle();}}public function fetchAll($offset=NULL,$limit=NULL){return$this->connection->query($this->_export(NULL,array('%ofs %lmt',$offset,$limit)))->fetchAll();}public function fetchAssoc($assoc){return$this->connection->query($this->_export())->fetchAssoc($assoc);}public function fetchPairs($key=NULL,$value=NULL){return$this->connection->query($this->_export())->fetchPairs($key,$value);}public function getIterator($offset=NULL,$limit=NULL){return$this->connection->query($this->_export(NULL,array('%ofs %lmt',$offset,$limit)))->getIterator();}public function test($clause=NULL){return$this->connection->test($this->_export($clause));}public function count(){return(int)$this->connection->query('SELECT COUNT(*) FROM (%ex',$this->_export(),') AS [data]')->fetchSingle();}public function toDataSource(){return new DibiDataSource($this->connection->sql($this->_export()),$this->connection);}final public function __toString(){return$this->connection->sql($this->_export());}protected function _export($clause=NULL,$args=array()){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();}}foreach($data as$clause=>$statement){if($statement!==NULL){$args[]=$clause;if($clause===$this->command){$args[]=implode(' ',array_keys($this->flags));}array_splice($args,count($args),0,$statement);}}return$args;}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));}}if(!function_exists('array_fill_keys')){function array_fill_keys($keys,$value){return array_combine($keys,array_fill(0,count($keys),$value));}}class DibiDatabaseInfo extends DibiObject{private$driver;private$name;private$tables;public function __construct(IDibiDriver$driver,$name){$this->driver=$driver;$this->name=$name;}public function getName(){return$this->name;}public function getTables(){$this->init();return array_values($this->tables);}public function getTableNames(){$this->init();$res=array();foreach($this->tables as$table){$res[]=$table->getName();}return$res;}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'.");}}public function hasTable($name){$this->init();return isset($this->tables[strtolower($name)]);}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);}}}}class DibiTableInfo extends DibiObject{private$driver;private$name;private$view;private$columns;private$foreignKeys;private$indexes;private$primaryKey;public function __construct(IDibiDriver$driver,array$info){$this->driver=$driver;$this->name=$info['name'];$this->view=!empty($info['view']);}public function getName(){return$this->name;}public function isView(){return$this->view;}public function getColumns(){$this->initColumns();return array_values($this->columns);}public function getColumnNames(){$this->initColumns();$res=array();foreach($this->columns as$column){$res[]=$column->getName();}return$res;}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'.");}}public function hasColumn($name){$this->initColumns();return isset($this->columns[strtolower($name)]);}public function getForeignKeys(){$this->initForeignKeys();return$this->foreignKeys;}public function getIndexes(){$this->initIndexes();return$this->indexes;}public function getPrimaryKey(){$this->initIndexes();return$this->primaryKey;}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);}}}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'])];}}}}protected function initForeignKeys(){throw new NotImplementedException;}}class DibiColumnInfo extends DibiObject{private static$types;private$driver;private$info;private$type;public function __construct(IDibiDriver$driver,array$info){$this->driver=$driver;$this->info=$info;$this->type=self::detectType($this->info['nativetype']);}public function getName(){return$this->info['name'];}public function hasTable(){return!empty($this->info['table']);}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']));}public function getType(){return$this->type;}public function getNativeType(){return$this->info['nativetype'];}public function getSize(){return isset($this->info['size'])?(int)$this->info['size']:NULL;}public function isNullable(){return isset($this->info['nullable'])?(bool)$this->info['nullable']:NULL;}public function isAutoIncrement(){return isset($this->info['autoincrement'])?(bool)$this->info['autoincrement']:NULL;}public function getDefault(){return isset($this->info['default'])?$this->info['default']:NULL;}public function getVendorInfo($key){return isset($this->info['vendor'][$key])?$this->info['vendor'][$key]:NULL;}public static function detectType($type){static$patterns=array('BYTEA|BLOB|BIN'=>dibi::BINARY,'BYTE|COUNTER|SERIAL|INT|LONG'=>dibi::INTEGER,'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER'=>dibi::FLOAT,'^TIME$'=>dibi::TIME,'TIME'=>dibi::DATETIME,'YEAR|DATE'=>dibi::DATE,'BOOL|BIT'=>dibi::BOOL);if(!isset(self::$types[$type])){self::$types[$type]=dibi::TEXT;foreach($patterns as$s=>$val){if(preg_match("#$s#i",$type)){return self::$types[$type]=$val;}}}return self::$types[$type];}}class DibiForeignKeyInfo extends DibiObject{private$name;private$references;public function __construct($name,array$references){$this->name=$name;$this->references=$references;}public function getName(){return$this->name;}public function getReferences(){return$this->references;}}class DibiIndexInfo extends DibiObject{private$info;public function __construct(array$info){$this->info=$info;}public function getName(){return$this->info['name'];}public function getColumns(){return$this->info['columns'];}public function isUnique(){return!empty($this->info['unique']);}public function isPrimary(){return!empty($this->info['primary']);}}class DibiProfiler extends DibiObject implements IDibiProfiler{private$file;public$useFirebug;private$filter=self::ALL;public$tickets=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/');}public function setFile($file){$this->file=$file;}public function setFilter($filter){$this->filter=(int)$filter;}public function before(DibiConnection$connection,$event,$sql=NULL){$this->tickets[]=array($connection,$event,$sql);end($this->tickets);return key($this->tickets);}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&&!headers_sent()){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|\\");}header("X-Wf-dibi-1-1-d$num: |$s|");}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");}}}public function exception(DibiDriverException$exception){if((self::EXCEPTION&$this->filter)===0)return;if($this->useFirebug){}if($this->file){$message=$exception->getMessage();$code=$exception->getCode();if($code){$message="[$code] $message";}$this->writeFile("ERROR: $message"."\n-- SQL: ".dibi::$sql."\n-- driver: ".";\n-- ".date('Y-m-d H:i:s')."\n\n");}}private function writeFile($message){$handle=fopen($this->file,'a');if(!$handle)return;flock($handle,LOCK_EX);fwrite($handle,$message);fclose($handle);}public static function json_encode($val){if(is_array($val)&&(!$val||array_keys($val)===range(0,count($val)-1))){return'['.implode(',',array_map(array(__CLASS__,'json_encode'),$val)).']';}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);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';}}class dibi{const TEXT='s';const BINARY='bin';const BOOL='b';const INTEGER='i';const FLOAT='f';const DATE='d';const DATETIME='t';const TIME='t';const IDENTIFIER='n';const FIELD_TEXT=self::TEXT;const FIELD_BINARY=self::BINARY;const FIELD_BOOL=self::BOOL;const FIELD_INTEGER=self::INTEGER;const FIELD_FLOAT=self::FLOAT;const FIELD_DATE=self::DATE;const FIELD_DATETIME=self::DATETIME;const FIELD_TIME=self::TIME;const VERSION='1.01';const REVISION='209 released on 2009/03/19 13:18:16';const RESULT_WITH_TABLES='resultWithTables';const ROW_CLASS='rowClass';const ASC='ASC',DESC='DESC';private static$registry=array();private static$connection;public static$substs=array();public static$substFallBack=array(__CLASS__,'defaultSubstFallback');private static$handlers=array();public static$sql;public static$elapsedTime;public static$totalTime;public static$numOfQueries=0;public static$defaultDriver='mysql';final public function __construct(){throw new LogicException("Cannot instantiate static class ".get_class($this));}public static function connect($config=array(),$name=0){return self::$connection=self::$registry[$name]=new DibiConnection($config,$name);}public static function disconnect(){self::getConnection()->disconnect();}public static function isConnected(){return(self::$connection!==NULL)&&self::$connection->isConnected();}public static function getConnection($name=NULL){if($name===NULL){if(self::$connection===NULL){throw new DibiException('Dibi is not connected to database.');}return self::$connection;}if(!isset(self::$registry[$name])){throw new DibiException("There is no connection named '$name'.");}return self::$registry[$name];}public static function activate($name){self::$connection=self::getConnection($name);}public static function getProfiler(){return self::getConnection()->getProfiler();}public static function query($args){$args=func_get_args();return self::getConnection()->query($args);}public static function nativeQuery($sql){return self::getConnection()->nativeQuery($sql);}public static function test($args){$args=func_get_args();return self::getConnection()->test($args);}public static function dataSource($args){$args=func_get_args();return self::getConnection()->dataSource($args);}public static function fetch($args){$args=func_get_args();return self::getConnection()->query($args)->fetch();}public static function fetchAll($args){$args=func_get_args();return self::getConnection()->query($args)->fetchAll();}public static function fetchSingle($args){$args=func_get_args();return self::getConnection()->query($args)->fetchSingle();}public static function fetchPairs($args){$args=func_get_args();return self::getConnection()->query($args)->fetchPairs();}public static function getAffectedRows(){return self::getConnection()->getAffectedRows();}public static function affectedRows(){return self::getConnection()->getAffectedRows();}public static function getInsertId($sequence=NULL){return self::getConnection()->getInsertId($sequence);}public static function insertId($sequence=NULL){return self::getConnection()->getInsertId($sequence);}public static function begin($savepoint=NULL){self::getConnection()->begin($savepoint);}public static function commit($savepoint=NULL){self::getConnection()->commit($savepoint);}public static function rollback($savepoint=NULL){self::getConnection()->rollback($savepoint);}public static function getDatabaseInfo(){return self::getConnection()->getDatabaseInfo();}public static function loadFile($file){return self::getConnection()->loadFile($file);}public static function __callStatic($name,$args){return call_user_func_array(array(self::getConnection(),$name),$args);}public static function command(){return self::getConnection()->command();}public static function select($args){$args=func_get_args();return self::getConnection()->command()->__call('select',$args);}public static function update($table,array$args){return self::getConnection()->update($table,$args);}public static function insert($table,array$args){return self::getConnection()->insert($table,$args);}public static function delete($table){return self::getConnection()->delete($table);}public static function datetime($time=NULL){if($time===NULL){$time=time();}elseif(is_numeric($time)){$time=(int)$time;}elseif($time instanceof DateTime){$time=$time->format('U');}else{$time=strtotime($time);}return new DibiVariable($time,dibi::DATETIME);}public static function date($date=NULL){$var=self::datetime($date);$var->modifier=dibi::DATE;return$var;}public static function addSubst($expr,$subst){self::$substs[$expr]=$subst;}public static function removeSubst($expr){if($expr===TRUE){self::$substs=array();}else{unset(self::$substs[':'.$expr.':']);}}public static function setSubstFallback($callback){if(!is_callable($callback)){throw new InvalidArgumentException("Invalid callback.");}self::$substFallBack=$callback;}public static function defaultSubstFallback($expr){throw new InvalidStateException("Missing substitution for '$expr' expression.");}public static function dump($sql=NULL,$return=FALSE){ob_start();if($sql instanceof DibiResult){$sql->dump();}else{if($sql===NULL)$sql=self::$sql;static$keywords1='SELECT|UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';static$keywords2='ALL|DISTINCT|DISTINCTROW|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|LIKE|TRUE|FALSE';$sql=' '.$sql;$sql=preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i","\n\$1",$sql);$sql=preg_replace('#[ \t]{2,}#'," ",$sql);$sql=wordwrap($sql,100);$sql=htmlSpecialChars($sql);$sql=preg_replace("#\n{2,}#","\n",$sql);$sql=preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is",array('dibi','highlightCallback'),$sql);$sql=trim($sql);echo'<pre class="dump">',$sql,"</pre>\n";}if($return){return ob_get_clean();}else{ob_end_flush();}}private static function highlightCallback($matches){if(!empty($matches[1]))return'<em style="color:gray">'.$matches[1].'</em>';if(!empty($matches[2]))return'<strong style="color:red">'.$matches[2].'</strong>';if(!empty($matches[3]))return'<strong style="color:blue">'.$matches[3].'</strong>';if(!empty($matches[4]))return'<strong style="color:green">'.$matches[4].'</strong>';}public static function getColophon($sender=NULL){$arr=array('Number of SQL queries: '.dibi::$numOfQueries.(dibi::$totalTime===NULL?'':', elapsed time: '.sprintf('%0.3f',dibi::$totalTime*1000).' ms'));if($sender==='bluescreen'){$arr[]='dibi '.dibi::VERSION.' (revision '.dibi::REVISION.')';}return$arr;}}class DibiMySqlDriver extends DibiObject implements IDibiDriver{private$connection;private$resultSet;private$buffered;public function __construct(){if(!extension_loaded('mysql')){throw new DibiDriverException("PHP extension 'mysql' is not loaded.");}}public function connect(array&$config){DibiConnection::alias($config,'username','user');DibiConnection::alias($config,'password','pass');DibiConnection::alias($config,'host','hostname');DibiConnection::alias($config,'options');if(isset($config['resource'])){$this->connection=$config['resource'];}else{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']);}else{$this->connection=@mysql_pconnect($host,$config['username'],$config['password'],$config['options']);}}if(!is_resource($this->connection)){throw new DibiDriverException(mysql_error(),mysql_errno());}if(isset($config['charset'])){$ok=FALSE;if(function_exists('mysql_set_charset')){$ok=@mysql_set_charset($config['charset'],$this->connection);}if(!$ok){$ok=@mysql_query("SET NAMES '$config[charset]'",$this->connection);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)){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)){throw new DibiDriverException(mysql_error($this->connection),mysql_errno($this->connection));}}$this->buffered=empty($config['unbuffered']);}public function disconnect(){mysql_close($this->connection);}public function query($sql){if($this->buffered){$this->resultSet=@mysql_query($sql,$this->connection);}else{$this->resultSet=@mysql_unbuffered_query($sql,$this->connection);}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;}public function getInfo(){$res=array();preg_match_all('#(.+?): +(\d+) *#',mysql_info($this->connection),$matches,PREG_SET_ORDER);foreach($matches as$m){$res[$m[1]]=(int)$m[2];}return$res;}public function getAffectedRows(){return mysql_affected_rows($this->connection);}public function getInsertId($sequence){return mysql_insert_id($this->connection);}public function begin($savepoint=NULL){$this->query($savepoint?"SAVEPOINT $savepoint":'START TRANSACTION');}public function commit($savepoint=NULL){$this->query($savepoint?"RELEASE SAVEPOINT $savepoint":'COMMIT');}public function rollback($savepoint=NULL){$this->query($savepoint?"ROLLBACK TO SAVEPOINT $savepoint":'ROLLBACK');}public function getResource(){return$this->connection;}public function escape($value,$type){switch($type){case dibi::TEXT:return"'".mysql_real_escape_string($value,$this->connection)."'";case dibi::BINARY:return"_binary'".mysql_real_escape_string($value,$this->connection)."'";case dibi::IDENTIFIER:$value=str_replace('`','``',$value);return'`'.str_replace('.','`.`',$value).'`';case dibi::BOOL:return$value?1:0;case dibi::DATE:return date("'Y-m-d'",$value);case dibi::DATETIME:return date("'Y-m-d H:i:s'",$value);default:throw new InvalidArgumentException('Unsupported type.');}}public function unescape($value,$type){throw new InvalidArgumentException('Unsupported type.');}public function applyLimit(&$sql,$limit,$offset){if($limit<0&&$offset<1)return;$sql.=' LIMIT '.($limit<0?'18446744073709551615':(int)$limit).($offset>0?' OFFSET '.(int)$offset:'');}public function getRowCount(){if(!$this->buffered){throw new DibiDriverException('Row count is not available for unbuffered queries.');}return mysql_num_rows($this->resultSet);}public function fetch($assoc){return mysql_fetch_array($this->resultSet,$assoc?MYSQL_ASSOC:MYSQL_NUM);}public function seek($row){if(!$this->buffered){throw new DibiDriverException('Cannot seek an unbuffered result set.');}return mysql_data_seek($this->resultSet,$row);}public function free(){mysql_free_result($this->resultSet);$this->resultSet=NULL;}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;}public function getResultResource(){return$this->resultSet;}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;}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;}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);}public function getForeignKeys($table){throw new NotImplementedException;}}class DibiMySqliDriver extends DibiObject implements IDibiDriver{private$connection;private$resultSet;private$buffered;public function __construct(){if(!extension_loaded('mysqli')){throw new DibiDriverException("PHP extension 'mysqli' is not loaded.");}}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');if(isset($config['resource'])){$this->connection=$config['resource'];}else{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']);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','>=')){$ok=@mysqli_set_charset($this->connection,$config['charset']);}if(!$ok){$ok=@mysqli_query($this->connection,"SET NAMES '$config[charset]'");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]'")){throw new DibiDriverException(mysqli_error($this->connection),mysqli_errno($this->connection));}}$this->buffered=empty($config['unbuffered']);}public function disconnect(){mysqli_close($this->connection);}public function query($sql){$this->resultSet=@mysqli_query($this->connection,$sql,$this->buffered?MYSQLI_STORE_RESULT:MYSQLI_USE_RESULT);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;}public function getInfo(){$res=array();preg_match_all('#(.+?): +(\d+) *#',mysqli_info($this->connection),$matches,PREG_SET_ORDER);foreach($matches as$m){$res[$m[1]]=(int)$m[2];}return$res;}public function getAffectedRows(){return mysqli_affected_rows($this->connection);}public function getInsertId($sequence){return mysqli_insert_id($this->connection);}public function begin($savepoint=NULL){$this->query($savepoint?"SAVEPOINT $savepoint":'START TRANSACTION');}public function commit($savepoint=NULL){$this->query($savepoint?"RELEASE SAVEPOINT $savepoint":'COMMIT');}public function rollback($savepoint=NULL){$this->query($savepoint?"ROLLBACK TO SAVEPOINT $savepoint":'ROLLBACK');}public function getResource(){return$this->connection;}public function escape($value,$type){switch($type){case dibi::TEXT:return"'".mysqli_real_escape_string($this->connection,$value)."'";case dibi::BINARY:return"_binary'".mysqli_real_escape_string($this->connection,$value)."'";case dibi::IDENTIFIER:$value=str_replace('`','``',$value);return'`'.str_replace('.','`.`',$value).'`';case dibi::BOOL:return$value?1:0;case dibi::DATE:return date("'Y-m-d'",$value);case dibi::DATETIME:return date("'Y-m-d H:i:s'",$value);default:throw new InvalidArgumentException('Unsupported type.');}}public function unescape($value,$type){throw new InvalidArgumentException('Unsupported type.');}public function applyLimit(&$sql,$limit,$offset){if($limit<0&&$offset<1)return;$sql.=' LIMIT '.($limit<0?'18446744073709551615':(int)$limit).($offset>0?' OFFSET '.(int)$offset:'');}public function getRowCount(){if(!$this->buffered){throw new DibiDriverException('Row count is not available for unbuffered queries.');}return mysqli_num_rows($this->resultSet);}public function fetch($assoc){return mysqli_fetch_array($this->resultSet,$assoc?MYSQLI_ASSOC:MYSQLI_NUM);}public function seek($row){if(!$this->buffered){throw new DibiDriverException('Cannot seek an unbuffered result set.');}return mysqli_data_seek($this->resultSet,$row);}public function free(){mysqli_free_result($this->resultSet);$this->resultSet=NULL;}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;}public function getResultResource(){return$this->resultSet;}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;}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;}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);}public function getForeignKeys($table){throw new NotImplementedException;}}class DibiOdbcDriver extends DibiObject implements IDibiDriver{private$connection;private$resultSet;private$row=0;public function __construct(){if(!extension_loaded('odbc')){throw new DibiDriverException("PHP extension 'odbc' is not loaded.");}}public function connect(array&$config){DibiConnection::alias($config,'username','user');DibiConnection::alias($config,'password','pass');if(isset($config['resource'])){$this->connection=$config['resource'];}else{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']);}else{$this->connection=@odbc_pconnect($config['dsn'],$config['username'],$config['password']);}}if(!is_resource($this->connection)){throw new DibiDriverException(odbc_errormsg().' '.odbc_error());}}public function disconnect(){odbc_close($this->connection);}public function query($sql){$this->resultSet=@odbc_exec($this->connection,$sql);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;}public function getAffectedRows(){return odbc_num_rows($this->resultSet);}public function getInsertId($sequence){throw new NotSupportedException('ODBC does not support autoincrementing.');}public function begin($savepoint=NULL){if(!odbc_autocommit($this->connection,FALSE)){throw new DibiDriverException(odbc_errormsg($this->connection).' '.odbc_error($this->connection));}}public function commit($savepoint=NULL){if(!odbc_commit($this->connection)){throw new DibiDriverException(odbc_errormsg($this->connection).' '.odbc_error($this->connection));}odbc_autocommit($this->connection,TRUE);}public function rollback($savepoint=NULL){if(!odbc_rollback($this->connection)){throw new DibiDriverException(odbc_errormsg($this->connection).' '.odbc_error($this->connection));}odbc_autocommit($this->connection,TRUE);}public function getResource(){return$this->connection;}public function escape($value,$type){switch($type){case dibi::TEXT:case dibi::BINARY:return"'".str_replace("'","''",$value)."'";case dibi::IDENTIFIER:$value=str_replace(array('[',']'),array('[[',']]'),$value);return'['.str_replace('.','].[',$value).']';case dibi::BOOL:return$value?-1:0;case dibi::DATE:return date("#m/d/Y#",$value);case dibi::DATETIME:return date("#m/d/Y H:i:s#",$value);default:throw new InvalidArgumentException('Unsupported type.');}}public function unescape($value,$type){throw new InvalidArgumentException('Unsupported type.');}public function applyLimit(&$sql,$limit,$offset){if($limit>=0){$sql='SELECT TOP '.(int)$limit.' * FROM ('.$sql.')';}if($offset)throw new InvalidArgumentException('Offset is not implemented in driver odbc.');}public function getRowCount(){return odbc_num_rows($this->resultSet);}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;}}public function seek($row){$this->row=$row;return TRUE;}public function free(){odbc_free_result($this->resultSet);$this->resultSet=NULL;}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;}public function getResultResource(){return$this->resultSet;}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;}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;}public function getIndexes($table){throw new NotImplementedException;}public function getForeignKeys($table){throw new NotImplementedException;}}class DibiPdoDriver extends DibiObject implements IDibiDriver{private$connection;private$resultSet;private$affectedRows=FALSE;public function __construct(){if(!extension_loaded('pdo')){throw new DibiDriverException("PHP extension 'pdo' is not loaded.");}}public function connect(array&$config){DibiConnection::alias($config,'username','user');DibiConnection::alias($config,'password','pass');DibiConnection::alias($config,'dsn');DibiConnection::alias($config,'resource','pdo');DibiConnection::alias($config,'options');if($config['resource']instanceof PDO){$this->connection=$config['resource'];}else try{$this->connection=new PDO($config['dsn'],$config['username'],$config['password'],$config['options']);}catch(PDOException$e){throw new DibiDriverException($e->getMessage(),$e->getCode());}if(!$this->connection){throw new DibiDriverException('Connecting error.');}}public function disconnect(){$this->connection=NULL;}public function query($sql){$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;}}public function getAffectedRows(){return$this->affectedRows;}public function getInsertId($sequence){return$this->connection->lastInsertId();}public function begin($savepoint=NULL){if(!$this->connection->beginTransaction()){$err=$this->connection->errorInfo();throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]",$err[1]);}}public function commit($savepoint=NULL){if(!$this->connection->commit()){$err=$this->connection->errorInfo();throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]",$err[1]);}}public function rollback($savepoint=NULL){if(!$this->connection->rollBack()){$err=$this->connection->errorInfo();throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]",$err[1]);}}public function getResource(){return$this->connection;}public function escape($value,$type){switch($type){case dibi::TEXT:return$this->connection->quote($value,PDO::PARAM_STR);case dibi::BINARY:return$this->connection->quote($value,PDO::PARAM_LOB);case dibi::IDENTIFIER:switch($this->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':case'mssql':$value=str_replace(array('[',']'),array('[[',']]'),$value);return'['.str_replace('.','].[',$value).']';default:return$value;}case dibi::BOOL:return$this->connection->quote($value,PDO::PARAM_BOOL);case dibi::DATE:return date("'Y-m-d'",$value);case dibi::DATETIME:return date("'Y-m-d H:i:s'",$value);default:throw new InvalidArgumentException('Unsupported type.');}}public function unescape($value,$type){throw new InvalidArgumentException('Unsupported type.');}public function applyLimit(&$sql,$limit,$offset){if($limit<0&&$offset<1)return;switch($this->connection->getAttribute(PDO::ATTR_DRIVER_NAME)){case'mysql':$sql.=' LIMIT '.($limit<0?'18446744073709551615':(int)$limit).($offset>0?' OFFSET '.(int)$offset:'');break;case'pgsql':if($limit>=0)$sql.=' LIMIT '.(int)$limit;if($offset>0)$sql.=' OFFSET '.(int)$offset;break;case'sqlite':case'sqlite2':case'oci':$sql.=' LIMIT '.$limit.($offset>0?' OFFSET '.(int)$offset:'');break;case'odbc':case'mssql':if($offset<1){$sql='SELECT TOP '.(int)$limit.' * FROM ('.$sql.')';break;}default:throw new NotSupportedException('PDO or driver does not support applying limit or offset.');}}public function getRowCount(){throw new NotSupportedException('Row count is not available for unbuffered queries.');}public function fetch($assoc){return$this->resultSet->fetch($assoc?PDO::FETCH_ASSOC:PDO::FETCH_NUM);}public function seek($row){throw new NotSupportedException('Cannot seek an unbuffered result set.');}public function free(){$this->resultSet=NULL;}public function getColumnsMeta(){$count=$this->resultSet->columnCount();$res=array();for($i=0;$i<$count;$i++){$row=@$this->resultSet->getColumnMeta($i);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;}public function getResultResource(){return$this->resultSet;}public function getTables(){throw new NotImplementedException;}public function getColumns($table){throw new NotImplementedException;}public function getIndexes($table){throw new NotImplementedException;}public function getForeignKeys($table){throw new NotImplementedException;}}class DibiPostgreDriver extends DibiObject implements IDibiDriver{private$connection;private$resultSet;private$escMethod=FALSE;public function __construct(){if(!extension_loaded('pgsql')){throw new DibiDriverException("PHP extension 'pgsql' is not loaded.");}}public function connect(array&$config){if(isset($config['resource'])){$this->connection=$config['resource'];}else{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','>=');}public function disconnect(){pg_close($this->connection);}public function query($sql){$this->resultSet=@pg_query($this->connection,$sql);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;}public function getAffectedRows(){return pg_affected_rows($this->resultSet);}public function getInsertId($sequence){if($sequence===NULL){$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;}public function begin($savepoint=NULL){$this->query($savepoint?"SAVEPOINT $savepoint":'START TRANSACTION');}public function commit($savepoint=NULL){$this->query($savepoint?"RELEASE SAVEPOINT $savepoint":'COMMIT');}public function rollback($savepoint=NULL){$this->query($savepoint?"ROLLBACK TO SAVEPOINT $savepoint":'ROLLBACK');}public function getResource(){return$this->connection;}public function escape($value,$type){switch($type){case dibi::TEXT:if($this->escMethod){return"'".pg_escape_string($this->connection,$value)."'";}else{return"'".pg_escape_string($value)."'";}case dibi::BINARY:if($this->escMethod){return"'".pg_escape_bytea($this->connection,$value)."'";}else{return"'".pg_escape_bytea($value)."'";}case dibi::IDENTIFIER:$a=strrpos($value,'.');if($a===FALSE){return'"'.str_replace('"','""',$value).'"';}else{return substr($value,0,$a).'."'.str_replace('"','""',substr($value,$a+1)).'"';}case dibi::BOOL:return$value?'TRUE':'FALSE';case dibi::DATE:return date("'Y-m-d'",$value);case dibi::DATETIME:return date("'Y-m-d H:i:s'",$value);default:throw new InvalidArgumentException('Unsupported type.');}}public function unescape($value,$type){switch($type){case dibi::BINARY:return pg_unescape_bytea($value);default:throw new InvalidArgumentException('Unsupported type.');}}public function applyLimit(&$sql,$limit,$offset){if($limit>=0)$sql.=' LIMIT '.(int)$limit;if($offset>0)$sql.=' OFFSET '.(int)$offset;}public function getRowCount(){return pg_num_rows($this->resultSet);}public function fetch($assoc){return pg_fetch_array($this->resultSet,NULL,$assoc?PGSQL_ASSOC:PGSQL_NUM);}public function seek($row){return pg_result_seek($this->resultSet,$row);}public function free(){pg_free_result($this->resultSet);$this->resultSet=NULL;}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;}public function getResultResource(){return$this->resultSet;}public function getTables(){$version=pg_version($this->connection);if($version['server']<8){throw new DibiDriverException('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;}public function getColumns($table){$_table=$this->escape($table,dibi::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;}public function getIndexes($table){$_table=$this->escape($table,dibi::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);}public function getForeignKeys($table){throw new NotImplementedException;}}class DibiSqliteDriver extends DibiObject implements IDibiDriver{private$connection;private$resultSet;private$buffered;private$fmtDate,$fmtDateTime;private$dbcharset,$charset;public function __construct(){if(!extension_loaded('sqlite')){throw new DibiDriverException("PHP extension 'sqlite' is not loaded.");}}public function connect(array&$config){DibiConnection::alias($config,'database','file');$this->fmtDate=isset($config['formatDate'])?$config['formatDate']:'U';$this->fmtDateTime=isset($config['formatDateTime'])?$config['formatDateTime']:'U';$errorMsg='';if(isset($config['resource'])){$this->connection=$config['resource'];}elseif(empty($config['persistent'])){$this->connection=@sqlite_open($config['database'],0666,$errorMsg);}else{$this->connection=@sqlite_popen($config['database'],0666,$errorMsg);}if(!$this->connection){throw new DibiDriverException($errorMsg);}$this->buffered=empty($config['unbuffered']);$this->dbcharset=empty($config['dbcharset'])?'UTF-8':$config['dbcharset'];$this->charset=empty($config['charset'])?'UTF-8':$config['charset'];if(strcasecmp($this->dbcharset,$this->charset)===0){$this->dbcharset=$this->charset=NULL;}}public function disconnect(){sqlite_close($this->connection);}public function query($sql){if($this->dbcharset!==NULL){$sql=iconv($this->charset,$this->dbcharset.'//IGNORE',$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;}public function getAffectedRows(){return sqlite_changes($this->connection);}public function getInsertId($sequence){return sqlite_last_insert_rowid($this->connection);}public function begin($savepoint=NULL){$this->query('BEGIN');}public function commit($savepoint=NULL){$this->query('COMMIT');}public function rollback($savepoint=NULL){$this->query('ROLLBACK');}public function getResource(){return$this->connection;}public function escape($value,$type){switch($type){case dibi::TEXT:case dibi::BINARY:return"'".sqlite_escape_string($value)."'";case dibi::IDENTIFIER:return'['.str_replace('.','].[',strtr($value,'[]',' ')).']';case dibi::BOOL:return$value?1:0;case dibi::DATE:return date($this->fmtDate,$value);case dibi::DATETIME:return date($this->fmtDateTime,$value);default:throw new InvalidArgumentException('Unsupported type.');}}public function unescape($value,$type){throw new InvalidArgumentException('Unsupported type.');}public function applyLimit(&$sql,$limit,$offset){if($limit<0&&$offset<1)return;$sql.=' LIMIT '.$limit.($offset>0?' OFFSET '.(int)$offset:'');}public function getRowCount(){if(!$this->buffered){throw new DibiDriverException('Row count is not available for unbuffered queries.');}return sqlite_num_rows($this->resultSet);}public function fetch($assoc){$row=sqlite_fetch_array($this->resultSet,$assoc?SQLITE_ASSOC:SQLITE_NUM);$charset=$this->charset===NULL?NULL:$this->charset.'//TRANSLIT';if($row&&($assoc||$charset)){$tmp=array();foreach($row as$k=>$v){if($charset!==NULL&&is_string($v)){$v=iconv($this->dbcharset,$charset,$v);}$tmp[str_replace(array('[',']'),'',$k)]=$v;}return$tmp;}return$row;}public function seek($row){if(!$this->buffered){throw new DibiDriverException('Cannot seek an unbuffered result set.');}return sqlite_seek($this->resultSet,$row);}public function free(){$this->resultSet=NULL;}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;}public function getResultResource(){return$this->resultSet;}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=array();while($row=$this->fetch(TRUE)){$res[]=$row;}$this->free();return$res;}public function getColumns($table){throw new NotImplementedException;}public function getIndexes($table){throw new NotImplementedException;}public function getForeignKeys($table){throw new NotImplementedException;}public function registerFunction($name,$callback,$numArgs=-1){sqlite_create_function($this->connection,$name,$callback,$numArgs);}public function registerAggregateFunction($name,$rowCallback,$agrCallback,$numArgs=-1){sqlite_create_aggregate($this->connection,$name,$rowCallback,$agrCallback,$numArgs);}}
|