--- /dev/null
+<?
+/**MySQL adaptation of DB-Engine*/
+class PGsqlEngine extends DbEngine
+{
+ /**prefix for table names*/
+ protected $prefix="";
+
+ private $connstr;
+ private $dbhdl=false;
+ private $charset="UTF8";
+ private $intrans=false;
+ //used for table creation to work around mysql bugs
+ private $tableappend;
+
+ /**initialize driver*/
+ public function __construct($connstring)
+ {
+ $this->connstr=$connstring;
+ }
+
+ /**make sure it shuts down*/
+ public function __destruct()
+ {
+ //fail on the side of caution: roll back unless already released
+ if($this->intrans)
+ @$this->rollbackTransaction();
+ }
+
+ /**set a table-name prefix for the database*/
+ public function setPrefix($pre)
+ {
+ $this->prefix=$pre;
+ }
+
+ /**set the default charset for tables and connections*/
+ public function setCharacterSet($c)
+ {
+ $this->charset=$c;
+ }
+
+ public function tryConnect()
+ {
+ //connect
+ $this->dbhdl=pg_connect($this->connstr);
+ if($this->dbhdl===false)
+ die("Unable to connect to database system. Giving up.");
+ //select Unicode; TODO: fix it to be configurable
+ if(pg_set_client_encoding($this->charset)!=0)
+ die("Cannot set character set to ".$this->charset.", aborting.");
+ //make sure the DB is transaction safe
+ if(@pg_query($this->dbhdl,"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE")===false)
+ die("Cannot make this database transaction safe, aborting");
+ }
+
+ public function hasTable($tnm)
+ {
+ global $dbScheme;
+ if(!$dbScheme->hasTable($tnm))return false;
+ $res=@pg_query($this->dbhdl,"select * from ".$this->tableName($tnm)." where 1=2");
+ if($res===false)return false;
+ pg_free_result($res);
+ return true;
+ }
+ public function beginTransaction()
+ {
+ $res=@pg_query($this->dbhdl,$this->sqlBeginTransaction());
+ if($res===false)
+ $this->intrans=false;
+ else{
+ $this->intrans=pg_result_status($res)==PGSQL_COMMAND_OK;
+ pg_free_result($res);
+ }
+ return $this->intrans;
+ }
+
+ public function commitTransaction()
+ {
+ if(!$this->intrans)return false;
+ //otherwise commit
+ $this->intrans=false;
+ $res=@pg_query($this->dbhdl,$this->sqlCommitTransaction());
+ if($res!==false){
+ pg_free_result($res);
+ return true;
+ }else
+ return false;
+ }
+
+ public function rollbackTransaction()
+ {
+ $this->intrans=false;
+ //don't ask, just do (also catches implicit transactions)
+ $res=@pg_query($this->dbhdl,$this->sqlRollbackTransaction());
+ if($res!==false)pg_free_result($res);
+ }
+
+ protected function lockDB($wl)
+ {
+ global $dbScheme;
+ if(!$this->intrans)$this->beginTransaction();
+ $req="LOCK TABLE ";
+ $i=0;
+ foreach($dbScheme->backupTables() as $tab){
+ if($i)$req.=",";
+ $i++;
+ $req.=$this->tableName($tab);
+ }
+ $req.=" IN ACCESS EXCLUSIVE";
+ $res=@pg_query($this->dbhdl,$req);
+ if($res!==false)pg_free_result($res);
+ }
+
+ public function sqlBeginTransaction(){return "BEGIN";}
+
+ public function sqlCommitTransaction(){return "COMMIT";}
+
+ public function sqlRollbackTransaction(){return "ROLLBACK";}
+
+
+ public function select($table,$cols,$where="",$orderby="")
+ {
+ //actual select
+ $query=$this->sqlSelect($table,$cols,$where,$orderby);
+ if($this->transmode)$query.=" FOR UPDATE";
+ $res=@pg_query($this->dbhdl,$query);
+ if($res===false)return false;
+ //get column names and types
+ $nf=pg_num_fields($res);
+ $fnames=array();
+ global $dbScheme;
+ for($i=0;$i<$nf;$i++)
+ $fnames[$i]=pg_field_name($res,$i);
+ //convert data
+ $nr=pg_num_rows($res);
+ $ret=array();
+ for($i=0;$i<$nr;$i++){
+ $row=pg_fetch_row($res);
+ $crw=array();
+ for($j=0;$j<$nf;$j++){
+ $fn=$fnames[$j];
+ if($dbScheme->isIntColumn($table,$fn))$crw[$j]=$row[$j]+0;else
+ if($dbScheme->isBlobColumn($table,$fn))$crw[$j]=pg_unescape_bytea($row[$j]);else
+ if($dbScheme->isBoolColumn($table,$fn))$crw[$j]=$row[$j]=='t';
+ else $crw[$j]=$row[$j];
+ $crw[$fn]=$crw[$j];
+ }
+ $ret[]=$crw;
+ }
+ //free up resources and return
+ pg_free_result($res);
+ return $ret;
+ }
+
+ protected function createTable($tn,$t)
+ {
+ $sql=$this->sqlCreateTable($tn,$t);
+ $res=@pg_query($this->dbhdl,$sql);
+ if($res!==false){
+ pg_free_result($res);
+ return true;
+ }else
+ return false;
+ }
+
+ protected function sqlCreateTable($tn,$t)
+ {
+ //use standard SQL
+ $ret=parent::sqlCreateTable($tn,$t);
+ //append indizes
+ foreach($t as $col=>$def){
+ if(in_array("index",$def)){
+ $ftn=$this->tableName($tn);
+ $ret.=";CREATE INDEX ".$ftn."_".$col."_idx ON "
+ .$ftn."(".$col.")";
+ }
+ }
+ return $ret;
+ }
+
+ protected function tableName($tn)
+ {
+ return $this->prefix.$tn;
+ }
+
+ protected function dataType($type)
+ {
+ if($type=="int32"||$type=="enum"||$type=="enum32")return "INTEGER";
+ if($type=="int64"||$type=="enum64")return "BIGINT";
+ if($type=="seq32")return "SERIAL";
+ if($type=="seq64")return "BIGSERIAL";
+ if($type=="text")return "TEXT";
+ if($type=="blob")return "BYTEA"; //max.4GB of blob
+ $tpa=explode(":",$type);
+ if($tpa[0]=="string"){
+ if(isset($tpa[1]))
+ return "VARCHAR(".$tpa[1].")";
+ else
+ return "VARCHAR";
+ }
+ //fallback to SQL standard
+ return parent::dataType($type);
+ }
+
+ protected function columnFlag($flag,$col,$table)
+ {
+ //PostgreSQL does not mark columns for indexing directly
+ if($flag=="index"){
+ return "";
+ }
+ //fallback to SQL standard
+ return parent::columnFlag($flag,$col,$table);
+ }
+
+ public function insert($table,array $values)
+ {
+ $this->transmode=true;
+ $res=@pg_query($this->dbhdl,$this->sqlInsert($table,$values));
+ if($res===false)return false;
+ pg_free_result($res);
+ global $dbScheme;
+ $seq=$dbScheme->hasSequence($table);
+ if($seq!==false){
+ if(isset($values[$seq]))return $values[$seq];
+ $res=@pg_query($this->dbhdl,"select lastval()");
+ if(pg_num_rows($res)>0){
+ $row=pg_fetch_array($res);
+ $ret=$row[0];
+ }else{
+ $ret=true;
+ }
+ pg_free_result($res);
+ return $ret;
+ }else{
+ return true;
+ }
+ }
+
+ public function update($table,array $values,$where)
+ {
+ $this->transmode=true;
+ $res=@pg_query($this->dbhdl,$this->sqlUpdate($table,$values,$where));
+ if($res!==false){
+ $ret=pg_affected_rows($res);
+ pg_free_result($res);
+ return $ret;
+ }else return false;
+ }
+
+ public function deleteRows($table,$where)
+ {
+ $this->transmode=true;
+ $res=@pg_query($this->dbhdl,$this->sqlDelete($table,$where));
+ if($res!==false){
+ $ret=pg_affected_rows($res);
+ pg_free_result($res);
+ return $ret;
+ }else return false;
+ }
+
+ public function lastError()
+ {
+ return pg_last_error($this->dbhdl);
+ }
+
+ /**escapes strings; it uses mysqli_escape_string and encloses the value in ''*/
+ public function escapeString($s)
+ {
+ if($s === false||$s===null) return "NULL";
+ return "'".pg_escape_string($this->dbhdl,$s)."'";
+ }
+
+ /**escapes blobs; it uses mysqli_escape_string and encloses the value in '' - blobs are binary strings in MySQL*/
+ public function escapeBlob($s)
+ {
+ if($s === false||$s===null) return "NULL";
+ return "'".pg_escape_bytea($this->dbhdl,$s)."'";
+ }
+};
+
+?>
\ No newline at end of file