1 <?php
2 3 4 5 6 7 8 9 10
11
12 namespace Neevo\Drivers;
13
14 use DateTime;
15 use InvalidArgumentException;
16 use Neevo\BaseStatement;
17 use Neevo\DriverException;
18 use Neevo\DriverInterface;
19 use Neevo\Manager;
20
21
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
37 class PgSQLDriver implements DriverInterface {
38
39
40
41 private $resource;
42
43
44 private $affectedRows;
45
46
47 48 49 50
51 public function __construct(BaseStatement $statement = null){
52 if(!extension_loaded("pgsql"))
53 throw new DriverException("Cannot instantiate Neevo PgSQL driver - PHP extension 'pgsql' not loaded.");
54 if($statement instanceof BaseStatement)
55 parent::__construct($statement);
56 }
57
58
59 60 61 62 63
64 public function connect(array $config){
65
66 $defaults = array(
67 'resource' => null,
68 'persistent' => false,
69 'charset' => 'utf8'
70 );
71
72 $config += $defaults;
73
74 if(isset($config['string']))
75 $string = $config['string'];
76 else{
77
78 $string = '';
79 foreach(array('host', 'hostaddr', 'port', 'dbname', 'user', 'password', 'connect_timeout', 'options', 'sslmode', 'service') as $cfg){
80 if(isset($config[$cfg]))
81 $string .= "$cfg=$config[$cfg] ";
82 }
83 }
84
85
86 if(is_resource($config['resource']))
87 $connection = $config['resource'];
88 elseif($config['persistent'])
89 $connection = @pg_pconnect($string, PGSQL_CONNECT_FORCE_NEW);
90 else
91 $connection = @pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
92
93 if(!is_resource($connection))
94 throw new DriverException("Connection to database failed.");
95
96 $this->resource = $connection;
97
98
99 @pg_set_client_encoding($this->resource, $config['charset']);
100
101
102 if(isset($config['schema']))
103 $this->runQuery('SET search_path TO "' . $config['schema'] . '"');
104 }
105
106
107 108 109
110 public function closeConnection(){
111 @pg_close($this->resource);
112 }
113
114
115 116 117 118 119
120 public function freeResultSet($resultSet){
121 @pg_free_result($resultSet);
122 }
123
124
125 126 127 128 129 130
131 public function runQuery($queryString){
132 $this->affectedRows = false;
133
134 $result = @pg_query($this->resource, $queryString);
135 if($result === false)
136 throw new DriverException(pg_last_error($this->resource), null, $queryString);
137
138 $this->affectedRows = @pg_affected_rows($result);
139 return $result;
140 }
141
142
143 144 145 146
147 public function beginTransaction($savepoint = null){
148 $this->runQuery($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
149 }
150
151
152 153 154 155
156 public function commit($savepoint = null){
157 $this->runQuery($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
158 }
159
160
161 162 163 164
165 public function rollback($savepoint = null){
166 $this->runQuery($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
167 }
168
169
170 171 172 173 174
175 public function fetch($resultSet){
176 return @pg_fetch_assoc($resultSet);
177 }
178
179
180 181 182 183 184 185
186 public function seek($resultSet, $offset){
187 return @pg_result_seek($resultSet, $offset);
188 }
189
190
191 192 193 194
195 public function getInsertId(){
196 $result = $this->runQuery("SELECT LASTVAL()");
197 if(!$result)
198 return false;
199
200 $r = $this->fetch($result);
201 return is_array($r) ? reset($r) : false;
202 }
203
204
205 206 207 208
209 public function randomizeOrder(BaseStatement $statement){
210 $statement->order('RAND()');
211 }
212
213
214 215 216 217 218
219 public function getNumRows($resultSet){
220 return @pg_num_rows($resultSet);
221 }
222
223
224 225 226 227
228 public function getAffectedRows(){
229 return $this->affectedRows;
230 }
231
232
233 234 235 236 237 238 239
240 public function escape($value, $type){
241 switch($type){
242 case Manager::BOOL:
243 return $value ? 'TRUE' : 'FALSE';
244
245 case Manager::TEXT:
246 return "'" . pg_escape_string($this->resource, $value) . "'";
247
248 case Manager::BINARY:
249 return "'" . pg_escape_bytea($this->resource, $value) . "'";
250
251 case Manager::IDENTIFIER:
252 return '"' . str_replace('.', '"."', str_replace('"', '""', $value)) . '"';
253
254 case Manager::DATETIME:
255 return ($value instanceof DateTime) ? $value->format("'Y-m-d H:i:s'") : date("'Y-m-d H:i:s'", $value);
256
257 default:
258 throw new InvalidArgumentException('Unsupported data type.');
259 break;
260 }
261 }
262
263
264 265 266 267 268 269 270
271 public function unescape($value, $type){
272 if($type === Manager::BINARY)
273 return pg_unescape_bytea($value);
274 throw new InvalidArgumentException('Unsupported data type.');
275 }
276
277
278 279 280 281 282 283 284
285 public function getPrimaryKey($table){
286 $def = $this->fetch($this->runQuery("SELECT indexdef FROM pg_indexes WHERE indexname = '{$table}_pkey'"));
287 if(!$def)
288 return false;
289 $def = reset($def);
290 if(preg_match("~{$table}_pkey\s+ON\s+{$table}.*\((\w+).*\)~i", $def, $matches))
291 return $matches[1];
292 return false;
293 }
294
295
296 297 298 299 300 301
302 public function getColumnTypes($resultSet, $table){
303 if($table === null)
304 return array();
305 $cols = pg_meta_data($this->resource, $table);
306 foreach($cols as $key => $value){
307 $cols[$key] = preg_replace('~[^a-z]~i', '', $value['type']);
308 }
309 return $cols;
310 }
311
312
313 }
314