PgSQL.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2004-2009 by Konstantin V. Arkhipov                     *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Lesser General Public License as        *
00007  *   published by the Free Software Foundation; either version 3 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00019     final class PgSQL extends DB
00020     {
00024         public static function getDialect()
00025         {
00026             return PostgresDialect::me();
00027         }
00028         
00032         public function connect()
00033         {
00034             $conn =
00035                 "host={$this->hostname} user={$this->username}"
00036                 .($this->password ? " password={$this->password}" : null)
00037                 .($this->basename ? " dbname={$this->basename}" : null)
00038                 .($this->port ? " port={$this->port}" : null);
00039 
00040             if ($this->persistent)
00041                 $this->link = pg_pconnect($conn);
00042             else
00043                 $this->link = pg_connect($conn);
00044 
00045             if (!$this->link)
00046                 throw new DatabaseException(
00047                     'can not connect to PostgreSQL server: '.pg_errormessage()
00048                 );
00049             
00050             if ($this->encoding)
00051                 $this->setDbEncoding();
00052             
00053             pg_set_error_verbosity($this->link, PGSQL_ERRORS_VERBOSE);
00054 
00055             return $this;
00056         }
00057         
00061         public function disconnect()
00062         {
00063             if ($this->isConnected())
00064                 pg_close($this->link);
00065 
00066             return $this;
00067         }
00068         
00069         public function isConnected()
00070         {
00071             return is_resource($this->link);
00072         }
00073         
00078         public function obtainSequence($sequence)
00079         {
00080             $res = $this->queryRaw("select nextval('{$sequence}') as seq");
00081             $row = pg_fetch_assoc($res);
00082             pg_free_result($res);
00083             return $row['seq'];
00084         }
00085         
00089         public function setDbEncoding()
00090         {
00091             pg_set_client_encoding($this->link, $this->encoding);
00092             
00093             return $this;
00094         }
00095         
00100         public function queryRaw($queryString)
00101         {
00102             try {
00103                 return pg_query($this->link, $queryString);
00104             } catch (BaseException $e) {
00105                 // manual parsing, since pg_send_query() and
00106                 // pg_get_result() is too slow in our case
00107                 list($error, ) = explode("\n", pg_errormessage($this->link));
00108                 $code = substr($error, 8, 5);
00109                 
00110                 if ($code == PostgresError::UNIQUE_VIOLATION) {
00111                     $e = 'DuplicateObjectException';
00112                     $code = null;
00113                 } else
00114                     $e = 'PostgresDatabaseException';
00115                 
00116                 throw new $e($error.' - '.$queryString, $code);
00117             }
00118         }
00119 
00124         public function queryCount(Query $query)
00125         {
00126             return pg_affected_rows($this->queryNull($query));
00127         }
00128         
00129         public function queryRow(Query $query)
00130         {
00131             $res = $this->query($query);
00132             
00133             if ($this->checkSingle($res)) {
00134                 $ret = pg_fetch_assoc($res);
00135                 pg_free_result($res);
00136                 return $ret;
00137             } else
00138                 return null;
00139         }
00140         
00141         public function queryColumn(Query $query)
00142         {
00143             $res = $this->query($query);
00144             
00145             if ($res) {
00146                 $array = array();
00147 
00148                 while ($row = pg_fetch_row($res))
00149                     $array[] = $row[0];
00150 
00151                 pg_free_result($res);
00152                 return $array;
00153             } else
00154                 return null;
00155         }
00156         
00157         public function querySet(Query $query)
00158         {
00159             $res = $this->query($query);
00160             
00161             if ($res) {
00162                 $array = array();
00163 
00164                 while ($row = pg_fetch_assoc($res))
00165                     $array[] = $row;
00166 
00167                 pg_free_result($res);
00168                 return $array;
00169             } else
00170                 return null;
00171         }
00172         
00173         public function hasSequences()
00174         {
00175             return true;
00176         }
00177         
00182         public function getTableInfo($table)
00183         {
00184             static $types = array(
00185                 'time'          => DataType::TIME,
00186                 'date'          => DataType::DATE,
00187                 'timestamp'     => DataType::TIMESTAMP,
00188                 
00189                 'bool'          => DataType::BOOLEAN,
00190                 
00191                 'int2'          => DataType::SMALLINT,
00192                 'int4'          => DataType::INTEGER,
00193                 'int8'          => DataType::BIGINT,
00194                 'numeric'       => DataType::NUMERIC,
00195                 
00196                 'float4'        => DataType::REAL,
00197                 'float8'        => DataType::DOUBLE,
00198                 
00199                 'varchar'       => DataType::VARCHAR,
00200                 'bpchar'        => DataType::CHAR,
00201                 'text'          => DataType::TEXT,
00202                 
00203                 'bytea'         => DataType::BINARY,
00204                 
00205                 // unhandled types, not ours anyway
00206                 'tsvector'      => null,
00207                 'inet'          => null,
00208                 'ltree'         => null,
00209                 'hstore'        => null,
00210             );
00211             
00212             try {
00213                 $res = pg_meta_data($this->link, $table);
00214             } catch (BaseException $e) {
00215                 throw new ObjectNotFoundException(
00216                     "unknown table '{$table}'"
00217                 );
00218             }
00219             
00220             $table = new DBTable($table);
00221             
00222             foreach ($res as $name => $info) {
00223                 
00224                 Assert::isTrue(
00225                     array_key_exists($info['type'], $types),
00226                     
00227                     'unknown type "'
00228                     .$types[$info['type']]
00229                     .'" found in column "'.$name.'"'
00230                 );
00231                 
00232                 if (empty($types[$info['type']]))
00233                     continue;
00234                 
00235                 $column =
00236                     new DBColumn(
00237                         DataType::create($types[$info['type']])->
00238                         setNull(!$info['not null']),
00239                         
00240                         $name
00241                     );
00242                 
00243                 $table->addColumn($column);
00244             }
00245             
00246             return $table;
00247         }
00248         
00249         private function checkSingle($result)
00250         {
00251             if (pg_num_rows($result) > 1)
00252                 throw new TooManyRowsException(
00253                     'query returned too many rows (we need only one)'
00254                 );
00255             
00256             return $result;
00257         }
00258     }
00259 ?>