blob: aada164d069a545f4151af9263c2f3abcb84de4a [file] [log] [blame]
Derek Jones0b59f272008-05-13 04:22:33 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allardba0dd632007-03-07 12:10:58 +00002/**
Derek Allardd2df9bc2007-04-15 17:41:17 +00003 * CodeIgniter
Derek Allardba0dd632007-03-07 12:10:58 +00004 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Rick Ellis9ba2bf22008-09-12 23:34:39 +00009 * @copyright Copyright (c) 2008, EllisLab, Inc.
Derek Jones7a9193a2008-01-21 18:39:20 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
Derek Allardba0dd632007-03-07 12:10:58 +000012 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * Postgre Database Adapter Class
20 *
21 * Note: _DB is an extender class that the app controller
22 * creates dynamically based on whether the active record
23 * class is being used or not.
24 *
25 * @package CodeIgniter
26 * @subpackage Drivers
27 * @category Database
Derek Allard3d879d52008-01-18 19:41:32 +000028 * @author ExpressionEngine Dev Team
Derek Jones7a9193a2008-01-21 18:39:20 +000029 * @link http://codeigniter.com/user_guide/database/
Derek Allardba0dd632007-03-07 12:10:58 +000030 */
31class CI_DB_postgre_driver extends CI_DB {
32
33 /**
Derek Allard694b5b82007-12-18 15:58:03 +000034 * The syntax to count rows is slightly different across different
35 * database engines, so this string appears in each driver and is
36 * used for the count_all() and count_all_results() functions.
37 */
Derek Allard39b622d2008-01-16 21:10:09 +000038 var $_count_string = "SELECT COUNT(*) AS ";
Derek Allard6ddb5a12007-12-18 17:22:50 +000039 var $_random_keyword = ' RANDOM()'; // database specific random keyword
Derek Allard694b5b82007-12-18 15:58:03 +000040
41 /**
Rick Ellisb6ba6a32008-10-07 00:44:41 +000042 * Connection String
43 *
44 * @access private
45 * @return string
46 */
47 function _connect_string()
48 {
49 $components = array(
50 'hostname' => 'host',
51 'port' => 'port',
52 'database' => 'dbname',
53 'username' => 'user',
54 'password' => 'password'
55 );
56
57 $connect_string = "";
58 foreach ($components as $key => $val)
59 {
60 if (isset($this->$key) && $this->$key != '')
61 {
62 $connect_string .= " $val=".$this->$key;
63 }
64 }
65 return trim($connect_string);
66 }
67
68 // --------------------------------------------------------------------
69
70 /**
Derek Allardba0dd632007-03-07 12:10:58 +000071 * Non-persistent database connection
72 *
73 * @access private called by the base class
74 * @return resource
75 */
76 function db_connect()
Rick Ellisb6ba6a32008-10-07 00:44:41 +000077 {
78 return @pg_connect($this->_connect_string());
Derek Allardba0dd632007-03-07 12:10:58 +000079 }
80
81 // --------------------------------------------------------------------
82
83 /**
84 * Persistent database connection
85 *
86 * @access private called by the base class
87 * @return resource
88 */
89 function db_pconnect()
90 {
Rick Ellisb6ba6a32008-10-07 00:44:41 +000091 return @pg_pconnect($this->_connect_string());
Derek Allardba0dd632007-03-07 12:10:58 +000092 }
93
94 // --------------------------------------------------------------------
95
96 /**
97 * Select the database
98 *
99 * @access private called by the base class
100 * @return resource
101 */
102 function db_select()
103 {
104 // Not needed for Postgre so we'll return TRUE
105 return TRUE;
106 }
107
108 // --------------------------------------------------------------------
109
110 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000111 * Set client character set
112 *
113 * @access public
114 * @param string
115 * @param string
116 * @return resource
117 */
118 function db_set_charset($charset, $collation)
119 {
Rick Ellisff734012008-09-30 20:38:12 +0000120 // @todo - add support if needed
Derek Allard39b622d2008-01-16 21:10:09 +0000121 return TRUE;
122 }
123
124 // --------------------------------------------------------------------
125
126 /**
Derek Allardba0dd632007-03-07 12:10:58 +0000127 * Version number query string
128 *
129 * @access public
130 * @return string
131 */
132 function _version()
133 {
134 return "SELECT version() AS ver";
135 }
136
137 // --------------------------------------------------------------------
138
139 /**
140 * Execute the query
141 *
142 * @access private called by the base class
143 * @param string an SQL query
144 * @return resource
145 */
146 function _execute($sql)
147 {
148 $sql = $this->_prep_query($sql);
149 return @pg_query($this->conn_id, $sql);
150 }
151
152 // --------------------------------------------------------------------
153
154 /**
155 * Prep the query
156 *
157 * If needed, each database adapter can prep the query string
158 *
159 * @access private called by execute()
160 * @param string an SQL query
161 * @return string
162 */
163 function _prep_query($sql)
164 {
165 return $sql;
166 }
167
168 // --------------------------------------------------------------------
169
170 /**
171 * Begin Transaction
172 *
173 * @access public
174 * @return bool
175 */
176 function trans_begin($test_mode = FALSE)
177 {
Derek Jones0b59f272008-05-13 04:22:33 +0000178 if ( ! $this->trans_enabled)
Derek Allardba0dd632007-03-07 12:10:58 +0000179 {
180 return TRUE;
181 }
182
183 // When transactions are nested we only begin/commit/rollback the outermost ones
184 if ($this->_trans_depth > 0)
185 {
186 return TRUE;
187 }
188
189 // Reset the transaction failure flag.
190 // If the $test_mode flag is set to TRUE transactions will be rolled back
191 // even if the queries produce a successful result.
192 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
193
194 return @pg_exec($this->conn_id, "begin");
195 }
196
197 // --------------------------------------------------------------------
198
199 /**
200 * Commit Transaction
201 *
202 * @access public
203 * @return bool
204 */
205 function trans_commit()
206 {
Derek Jones0b59f272008-05-13 04:22:33 +0000207 if ( ! $this->trans_enabled)
Derek Allardba0dd632007-03-07 12:10:58 +0000208 {
209 return TRUE;
210 }
211
212 // When transactions are nested we only begin/commit/rollback the outermost ones
213 if ($this->_trans_depth > 0)
214 {
215 return TRUE;
216 }
217
218 return @pg_exec($this->conn_id, "commit");
219 }
220
221 // --------------------------------------------------------------------
222
223 /**
224 * Rollback Transaction
225 *
226 * @access public
227 * @return bool
228 */
229 function trans_rollback()
230 {
Derek Jones0b59f272008-05-13 04:22:33 +0000231 if ( ! $this->trans_enabled)
Derek Allardba0dd632007-03-07 12:10:58 +0000232 {
233 return TRUE;
234 }
235
236 // When transactions are nested we only begin/commit/rollback the outermost ones
237 if ($this->_trans_depth > 0)
238 {
239 return TRUE;
240 }
241
242 return @pg_exec($this->conn_id, "rollback");
243 }
244
245 // --------------------------------------------------------------------
246
247 /**
248 * Escape String
249 *
250 * @access public
251 * @param string
252 * @return string
253 */
254 function escape_str($str)
255 {
256 return pg_escape_string($str);
257 }
258
259 // --------------------------------------------------------------------
260
261 /**
262 * Affected Rows
263 *
264 * @access public
265 * @return integer
266 */
267 function affected_rows()
268 {
269 return @pg_affected_rows($this->result_id);
270 }
271
272 // --------------------------------------------------------------------
273
274 /**
275 * Insert ID
276 *
277 * @access public
278 * @return integer
279 */
280 function insert_id()
281 {
Derek Jonesf9a4e9e2007-07-12 13:56:21 +0000282 $v = $this->_version();
Derek Allardba0dd632007-03-07 12:10:58 +0000283 $v = $v['server'];
284
285 $table = func_num_args() > 0 ? func_get_arg(0) : null;
286 $column = func_num_args() > 1 ? func_get_arg(1) : null;
287
288 if ($table == null && $v >= '8.1')
289 {
290 $sql='SELECT LASTVAL() as ins_id';
291 }
292 elseif ($table != null && $column != null && $v >= '8.0')
293 {
294 $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column);
295 $query = $this->query($sql);
296 $row = $query->row();
297 $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq);
298 }
299 elseif ($table != null)
300 {
301 // seq_name passed in table parameter
302 $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table);
303 }
304 else
305 {
306 return pg_last_oid($this->result_id);
307 }
308 $query = $this->query($sql);
309 $row = $query->row();
310 return $row->ins_id;
311 }
312
313 // --------------------------------------------------------------------
314
315 /**
316 * "Count All" query
317 *
318 * Generates a platform-specific query string that counts all records in
319 * the specified database
320 *
321 * @access public
322 * @param string
323 * @return string
324 */
325 function count_all($table = '')
326 {
327 if ($table == '')
328 return '0';
Derek Allard694b5b82007-12-18 15:58:03 +0000329
Derek Allardf6cd45c2008-01-18 14:31:51 +0000330 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));
Derek Allard694b5b82007-12-18 15:58:03 +0000331
Derek Allardba0dd632007-03-07 12:10:58 +0000332 if ($query->num_rows() == 0)
333 return '0';
334
335 $row = $query->row();
336 return $row->numrows;
337 }
338
339 // --------------------------------------------------------------------
340
341 /**
342 * Show table query
343 *
344 * Generates a platform-specific query string so that the table names can be fetched
345 *
346 * @access private
Derek Allard39b622d2008-01-16 21:10:09 +0000347 * @param boolean
Derek Allardba0dd632007-03-07 12:10:58 +0000348 * @return string
349 */
Derek Allard39b622d2008-01-16 21:10:09 +0000350 function _list_tables($prefix_limit = FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000351 {
Derek Allard39b622d2008-01-16 21:10:09 +0000352 $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'";
353
354 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
355 {
356 $sql .= " AND table_name LIKE '".$this->dbprefix."%'";
357 }
358
359 return $sql;
Derek Allardba0dd632007-03-07 12:10:58 +0000360 }
361
362 // --------------------------------------------------------------------
363
364 /**
365 * Show column query
366 *
367 * Generates a platform-specific query string so that the column names can be fetched
368 *
369 * @access public
370 * @param string the table name
371 * @return string
372 */
373 function _list_columns($table = '')
374 {
Derek Allard694b5b82007-12-18 15:58:03 +0000375 return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$this->_escape_table($table)."'";
Derek Allardba0dd632007-03-07 12:10:58 +0000376 }
377
378 // --------------------------------------------------------------------
379
380 /**
381 * Field data query
382 *
383 * Generates a platform-specific query so that the column data can be retrieved
384 *
385 * @access public
386 * @param string the table name
387 * @return object
388 */
389 function _field_data($table)
390 {
391 return "SELECT * FROM ".$this->_escape_table($table)." LIMIT 1";
392 }
393
394 // --------------------------------------------------------------------
395
396 /**
397 * The error message string
398 *
399 * @access private
400 * @return string
401 */
402 function _error_message()
403 {
404 return pg_last_error($this->conn_id);
405 }
406
407 // --------------------------------------------------------------------
408
409 /**
410 * The error message number
411 *
412 * @access private
413 * @return integer
414 */
415 function _error_number()
416 {
417 return '';
418 }
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000419 // --------------------------------------------------------------------
420
421 /**
422 * Escape Column Name
423 *
424 * This function adds backticks around supplied column name
425 *
426 * @access private
427 * @param string the column name
428 * @return string
429 */
430 function _escape_column($column)
431 {
432 // Probably not necessary with Postgres so we simply return the value
433 return $column;
434 }
435
Derek Allardba0dd632007-03-07 12:10:58 +0000436 // --------------------------------------------------------------------
437
438 /**
439 * Escape Table Name
440 *
441 * This function adds backticks if the table name has a period
442 * in it. Some DBs will get cranky unless periods are escaped.
443 *
444 * @access private
445 * @param string the table name
446 * @return string
447 */
448 function _escape_table($table)
449 {
Derek Allardc0743382008-02-11 05:54:44 +0000450 if (strpos($table, '.') !== FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000451 {
Derek Allardc0743382008-02-11 05:54:44 +0000452 $table = '"' . str_replace('.', '"."', $table) . '"';
Derek Allardba0dd632007-03-07 12:10:58 +0000453 }
454
455 return $table;
456 }
457
458 // --------------------------------------------------------------------
459
460 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000461 * Protect Identifiers
462 *
463 * This function adds backticks if appropriate based on db type
464 *
465 * @access private
466 * @param mixed the item to escape
467 * @param boolean only affect the first word
468 * @return mixed the item with backticks
469 */
470 function _protect_identifiers($item, $first_word_only = FALSE)
471 {
472 if (is_array($item))
473 {
474 $escaped_array = array();
475
476 foreach($item as $k=>$v)
477 {
478 $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);
479 }
480
481 return $escaped_array;
482 }
483
484 // This function may get "item1 item2" as a string, and so
485 // we may need ""item1" "item2"" and not ""item1 item2""
Derek Allard61579382008-01-16 22:22:42 +0000486 if (ctype_alnum($item) === FALSE)
Derek Allard39b622d2008-01-16 21:10:09 +0000487 {
Derek Allard9b3e7b52008-02-04 23:20:34 +0000488 if (strpos($item, '.') !== FALSE)
489 {
490 $aliased_tables = implode(".",$this->ar_aliased_tables).'.';
491 $table_name = substr($item, 0, strpos($item, '.')+1);
492 $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;
493 }
494
Derek Allard39b622d2008-01-16 21:10:09 +0000495 // This function may get "field >= 1", and need it to return ""field" >= 1"
Derek Allard61579382008-01-16 22:22:42 +0000496 $lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';
Derek Allard39b622d2008-01-16 21:10:09 +0000497
Derek Allard61579382008-01-16 22:22:42 +0000498 $item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1"$2"$3', $item);
499 }
500 else
501 {
Derek Allard4acd7922008-01-26 19:33:59 +0000502 return "\"{$item}\"";
Derek Allard39b622d2008-01-16 21:10:09 +0000503 }
504
Derek Allard9a4d1da2008-02-25 14:18:38 +0000505 $exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');
Derek Allard39b622d2008-01-16 21:10:09 +0000506
507 foreach ($exceptions as $exception)
508 {
Derek Allard61579382008-01-16 22:22:42 +0000509
Derek Allard4acd7922008-01-26 19:33:59 +0000510 if (stristr($item, " \"{$exception}\" ") !== FALSE)
Derek Allard39b622d2008-01-16 21:10:09 +0000511 {
512 $item = preg_replace('/ "('.preg_quote($exception).')" /i', ' $1 ', $item);
513 }
514 }
Derek Allard39b622d2008-01-16 21:10:09 +0000515 return $item;
516 }
517
518 // --------------------------------------------------------------------
519
520 /**
Derek Jonesc6ad0232008-01-29 18:44:54 +0000521 * From Tables
522 *
523 * This function implicitly groups FROM tables so there is no confusion
524 * about operator precedence in harmony with SQL standards
525 *
526 * @access public
527 * @param type
528 * @return type
529 */
530 function _from_tables($tables)
531 {
Derek Jones0b59f272008-05-13 04:22:33 +0000532 if ( ! is_array($tables))
Derek Jonesc6ad0232008-01-29 18:44:54 +0000533 {
534 $tables = array($tables);
535 }
536
Derek Allard15648132008-02-10 21:46:18 +0000537 return implode(', ', $tables);
Derek Jonesc6ad0232008-01-29 18:44:54 +0000538 }
539
540 // --------------------------------------------------------------------
541
542 /**
Derek Allardba0dd632007-03-07 12:10:58 +0000543 * Insert statement
544 *
545 * Generates a platform-specific insert string from the supplied data
546 *
547 * @access public
548 * @param string the table name
549 * @param array the insert keys
550 * @param array the insert values
551 * @return string
552 */
553 function _insert($table, $keys, $values)
554 {
555 return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
556 }
557
558 // --------------------------------------------------------------------
559
560 /**
561 * Update statement
562 *
563 * Generates a platform-specific update string from the supplied data
564 *
565 * @access public
566 * @param string the table name
567 * @param array the update data
568 * @param array the where clause
Derek Allard39b622d2008-01-16 21:10:09 +0000569 * @param array the orderby clause
570 * @param array the limit clause
Derek Allardba0dd632007-03-07 12:10:58 +0000571 * @return string
572 */
Derek Allard39b622d2008-01-16 21:10:09 +0000573 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000574 {
575 foreach($values as $key => $val)
576 {
577 $valstr[] = $key." = ".$val;
578 }
Derek Allardda6d2402007-12-19 14:49:29 +0000579
Derek Jones0b59f272008-05-13 04:22:33 +0000580 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
Derek Allard39b622d2008-01-16 21:10:09 +0000581
582 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
Derek Allardba0dd632007-03-07 12:10:58 +0000583
Derek Allard32cf7eb2008-02-05 16:03:50 +0000584 $sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);
585 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
586 $sql .= $orderby.$limit;
587
588 return $sql;
Derek Allard39b622d2008-01-16 21:10:09 +0000589 }
590
591
592 // --------------------------------------------------------------------
593
594 /**
595 * Truncate statement
596 *
597 * Generates a platform-specific truncate string from the supplied data
598 * If the database does not support the truncate() command
599 * This function maps to "DELETE FROM table"
600 *
601 * @access public
602 * @param string the table name
603 * @return string
604 */
605 function _truncate($table)
606 {
607 return "TRUNCATE ".$this->_escape_table($table);
Derek Allardba0dd632007-03-07 12:10:58 +0000608 }
609
610 // --------------------------------------------------------------------
611
612 /**
613 * Delete statement
614 *
615 * Generates a platform-specific delete string from the supplied data
616 *
617 * @access public
618 * @param string the table name
619 * @param array the where clause
Derek Allard39b622d2008-01-16 21:10:09 +0000620 * @param string the limit clause
Derek Allardba0dd632007-03-07 12:10:58 +0000621 * @return string
622 */
Derek Allard39b622d2008-01-16 21:10:09 +0000623 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000624 {
Derek Allard39b622d2008-01-16 21:10:09 +0000625 $conditions = '';
626
Derek Jones0b59f272008-05-13 04:22:33 +0000627 if (count($where) > 0 OR count($like) > 0)
Derek Allard39b622d2008-01-16 21:10:09 +0000628 {
629 $conditions = "\nWHERE ";
630 $conditions .= implode("\n", $this->ar_where);
631
632 if (count($where) > 0 && count($like) > 0)
633 {
634 $conditions .= " AND ";
635 }
636 $conditions .= implode("\n", $like);
637 }
638
Derek Jones0b59f272008-05-13 04:22:33 +0000639 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
Derek Allarde77d77c2007-12-19 15:01:55 +0000640
Derek Allard39b622d2008-01-16 21:10:09 +0000641 return "DELETE FROM ".$table.$conditions.$limit;
Derek Allardba0dd632007-03-07 12:10:58 +0000642 }
643
644 // --------------------------------------------------------------------
Derek Allardba0dd632007-03-07 12:10:58 +0000645 /**
646 * Limit string
647 *
648 * Generates a platform-specific LIMIT clause
649 *
650 * @access public
651 * @param string the sql query string
652 * @param integer the number of rows to limit the query to
653 * @param integer the offset value
654 * @return string
655 */
656 function _limit($sql, $limit, $offset)
657 {
658 $sql .= "LIMIT ".$limit;
659
660 if ($offset > 0)
661 {
662 $sql .= " OFFSET ".$offset;
663 }
664
665 return $sql;
666 }
667
668 // --------------------------------------------------------------------
669
670 /**
671 * Close DB Connection
672 *
673 * @access public
674 * @param resource
675 * @return void
676 */
677 function _close($conn_id)
678 {
679 @pg_close($conn_id);
680 }
681
682
683}
684
Derek Jones0b59f272008-05-13 04:22:33 +0000685
686/* End of file postgre_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000687/* Location: ./system/database/drivers/postgre/postgre_driver.php */