blob: c5c70a736dcf483f7f94e0d86b0cc776abfc585c [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
Rick Ellis5aa8c602008-10-07 01:24:07 +000033 var $dbdriver = 'postgre';
34
Derek Allardba0dd632007-03-07 12:10:58 +000035 /**
Derek Allard694b5b82007-12-18 15:58:03 +000036 * The syntax to count rows is slightly different across different
37 * database engines, so this string appears in each driver and is
38 * used for the count_all() and count_all_results() functions.
39 */
Derek Allard39b622d2008-01-16 21:10:09 +000040 var $_count_string = "SELECT COUNT(*) AS ";
Derek Allard6ddb5a12007-12-18 17:22:50 +000041 var $_random_keyword = ' RANDOM()'; // database specific random keyword
Derek Allard694b5b82007-12-18 15:58:03 +000042
43 /**
Rick Ellisb6ba6a32008-10-07 00:44:41 +000044 * Connection String
45 *
46 * @access private
47 * @return string
48 */
49 function _connect_string()
50 {
51 $components = array(
52 'hostname' => 'host',
53 'port' => 'port',
54 'database' => 'dbname',
55 'username' => 'user',
56 'password' => 'password'
57 );
58
59 $connect_string = "";
60 foreach ($components as $key => $val)
61 {
62 if (isset($this->$key) && $this->$key != '')
63 {
64 $connect_string .= " $val=".$this->$key;
65 }
66 }
67 return trim($connect_string);
68 }
69
70 // --------------------------------------------------------------------
71
72 /**
Derek Allardba0dd632007-03-07 12:10:58 +000073 * Non-persistent database connection
74 *
75 * @access private called by the base class
76 * @return resource
77 */
78 function db_connect()
Rick Ellisb6ba6a32008-10-07 00:44:41 +000079 {
80 return @pg_connect($this->_connect_string());
Derek Allardba0dd632007-03-07 12:10:58 +000081 }
82
83 // --------------------------------------------------------------------
84
85 /**
86 * Persistent database connection
87 *
88 * @access private called by the base class
89 * @return resource
90 */
91 function db_pconnect()
92 {
Rick Ellisb6ba6a32008-10-07 00:44:41 +000093 return @pg_pconnect($this->_connect_string());
Derek Allardba0dd632007-03-07 12:10:58 +000094 }
95
96 // --------------------------------------------------------------------
97
98 /**
99 * Select the database
100 *
101 * @access private called by the base class
102 * @return resource
103 */
104 function db_select()
105 {
106 // Not needed for Postgre so we'll return TRUE
107 return TRUE;
108 }
109
110 // --------------------------------------------------------------------
111
112 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000113 * Set client character set
114 *
115 * @access public
116 * @param string
117 * @param string
118 * @return resource
119 */
120 function db_set_charset($charset, $collation)
121 {
Rick Ellisff734012008-09-30 20:38:12 +0000122 // @todo - add support if needed
Derek Allard39b622d2008-01-16 21:10:09 +0000123 return TRUE;
124 }
125
126 // --------------------------------------------------------------------
127
128 /**
Derek Allardba0dd632007-03-07 12:10:58 +0000129 * Version number query string
130 *
131 * @access public
132 * @return string
133 */
134 function _version()
135 {
136 return "SELECT version() AS ver";
137 }
138
139 // --------------------------------------------------------------------
140
141 /**
142 * Execute the query
143 *
144 * @access private called by the base class
145 * @param string an SQL query
146 * @return resource
147 */
148 function _execute($sql)
149 {
150 $sql = $this->_prep_query($sql);
151 return @pg_query($this->conn_id, $sql);
152 }
153
154 // --------------------------------------------------------------------
155
156 /**
157 * Prep the query
158 *
159 * If needed, each database adapter can prep the query string
160 *
161 * @access private called by execute()
162 * @param string an SQL query
163 * @return string
164 */
165 function _prep_query($sql)
166 {
167 return $sql;
168 }
169
170 // --------------------------------------------------------------------
171
172 /**
173 * Begin Transaction
174 *
175 * @access public
176 * @return bool
177 */
178 function trans_begin($test_mode = FALSE)
179 {
Derek Jones0b59f272008-05-13 04:22:33 +0000180 if ( ! $this->trans_enabled)
Derek Allardba0dd632007-03-07 12:10:58 +0000181 {
182 return TRUE;
183 }
184
185 // When transactions are nested we only begin/commit/rollback the outermost ones
186 if ($this->_trans_depth > 0)
187 {
188 return TRUE;
189 }
190
191 // Reset the transaction failure flag.
192 // If the $test_mode flag is set to TRUE transactions will be rolled back
193 // even if the queries produce a successful result.
194 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
195
196 return @pg_exec($this->conn_id, "begin");
197 }
198
199 // --------------------------------------------------------------------
200
201 /**
202 * Commit Transaction
203 *
204 * @access public
205 * @return bool
206 */
207 function trans_commit()
208 {
Derek Jones0b59f272008-05-13 04:22:33 +0000209 if ( ! $this->trans_enabled)
Derek Allardba0dd632007-03-07 12:10:58 +0000210 {
211 return TRUE;
212 }
213
214 // When transactions are nested we only begin/commit/rollback the outermost ones
215 if ($this->_trans_depth > 0)
216 {
217 return TRUE;
218 }
219
220 return @pg_exec($this->conn_id, "commit");
221 }
222
223 // --------------------------------------------------------------------
224
225 /**
226 * Rollback Transaction
227 *
228 * @access public
229 * @return bool
230 */
231 function trans_rollback()
232 {
Derek Jones0b59f272008-05-13 04:22:33 +0000233 if ( ! $this->trans_enabled)
Derek Allardba0dd632007-03-07 12:10:58 +0000234 {
235 return TRUE;
236 }
237
238 // When transactions are nested we only begin/commit/rollback the outermost ones
239 if ($this->_trans_depth > 0)
240 {
241 return TRUE;
242 }
243
244 return @pg_exec($this->conn_id, "rollback");
245 }
246
247 // --------------------------------------------------------------------
248
249 /**
250 * Escape String
251 *
252 * @access public
253 * @param string
254 * @return string
255 */
256 function escape_str($str)
257 {
258 return pg_escape_string($str);
259 }
260
261 // --------------------------------------------------------------------
262
263 /**
264 * Affected Rows
265 *
266 * @access public
267 * @return integer
268 */
269 function affected_rows()
270 {
271 return @pg_affected_rows($this->result_id);
272 }
273
274 // --------------------------------------------------------------------
275
276 /**
277 * Insert ID
278 *
279 * @access public
280 * @return integer
281 */
282 function insert_id()
283 {
Derek Jonesf9a4e9e2007-07-12 13:56:21 +0000284 $v = $this->_version();
Derek Allardba0dd632007-03-07 12:10:58 +0000285 $v = $v['server'];
286
287 $table = func_num_args() > 0 ? func_get_arg(0) : null;
288 $column = func_num_args() > 1 ? func_get_arg(1) : null;
289
290 if ($table == null && $v >= '8.1')
291 {
292 $sql='SELECT LASTVAL() as ins_id';
293 }
294 elseif ($table != null && $column != null && $v >= '8.0')
295 {
296 $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column);
297 $query = $this->query($sql);
298 $row = $query->row();
299 $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq);
300 }
301 elseif ($table != null)
302 {
303 // seq_name passed in table parameter
304 $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table);
305 }
306 else
307 {
308 return pg_last_oid($this->result_id);
309 }
310 $query = $this->query($sql);
311 $row = $query->row();
312 return $row->ins_id;
313 }
314
315 // --------------------------------------------------------------------
316
317 /**
318 * "Count All" query
319 *
320 * Generates a platform-specific query string that counts all records in
321 * the specified database
322 *
323 * @access public
324 * @param string
325 * @return string
326 */
327 function count_all($table = '')
328 {
329 if ($table == '')
330 return '0';
Derek Allard694b5b82007-12-18 15:58:03 +0000331
Derek Allardf6cd45c2008-01-18 14:31:51 +0000332 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));
Derek Allard694b5b82007-12-18 15:58:03 +0000333
Derek Allardba0dd632007-03-07 12:10:58 +0000334 if ($query->num_rows() == 0)
335 return '0';
336
337 $row = $query->row();
338 return $row->numrows;
339 }
340
341 // --------------------------------------------------------------------
342
343 /**
344 * Show table query
345 *
346 * Generates a platform-specific query string so that the table names can be fetched
347 *
348 * @access private
Derek Allard39b622d2008-01-16 21:10:09 +0000349 * @param boolean
Derek Allardba0dd632007-03-07 12:10:58 +0000350 * @return string
351 */
Derek Allard39b622d2008-01-16 21:10:09 +0000352 function _list_tables($prefix_limit = FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000353 {
Derek Allard39b622d2008-01-16 21:10:09 +0000354 $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'";
355
356 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
357 {
358 $sql .= " AND table_name LIKE '".$this->dbprefix."%'";
359 }
360
361 return $sql;
Derek Allardba0dd632007-03-07 12:10:58 +0000362 }
363
364 // --------------------------------------------------------------------
365
366 /**
367 * Show column query
368 *
369 * Generates a platform-specific query string so that the column names can be fetched
370 *
371 * @access public
372 * @param string the table name
373 * @return string
374 */
375 function _list_columns($table = '')
376 {
Derek Allard694b5b82007-12-18 15:58:03 +0000377 return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$this->_escape_table($table)."'";
Derek Allardba0dd632007-03-07 12:10:58 +0000378 }
379
380 // --------------------------------------------------------------------
381
382 /**
383 * Field data query
384 *
385 * Generates a platform-specific query so that the column data can be retrieved
386 *
387 * @access public
388 * @param string the table name
389 * @return object
390 */
391 function _field_data($table)
392 {
393 return "SELECT * FROM ".$this->_escape_table($table)." LIMIT 1";
394 }
395
396 // --------------------------------------------------------------------
397
398 /**
399 * The error message string
400 *
401 * @access private
402 * @return string
403 */
404 function _error_message()
405 {
406 return pg_last_error($this->conn_id);
407 }
408
409 // --------------------------------------------------------------------
410
411 /**
412 * The error message number
413 *
414 * @access private
415 * @return integer
416 */
417 function _error_number()
418 {
419 return '';
420 }
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000421 // --------------------------------------------------------------------
422
423 /**
424 * Escape Column Name
425 *
426 * This function adds backticks around supplied column name
427 *
428 * @access private
429 * @param string the column name
430 * @return string
431 */
432 function _escape_column($column)
433 {
434 // Probably not necessary with Postgres so we simply return the value
435 return $column;
436 }
437
Derek Allardba0dd632007-03-07 12:10:58 +0000438 // --------------------------------------------------------------------
439
440 /**
441 * Escape Table Name
442 *
443 * This function adds backticks if the table name has a period
444 * in it. Some DBs will get cranky unless periods are escaped.
445 *
446 * @access private
447 * @param string the table name
448 * @return string
449 */
450 function _escape_table($table)
451 {
Derek Allardc0743382008-02-11 05:54:44 +0000452 if (strpos($table, '.') !== FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000453 {
Derek Allardc0743382008-02-11 05:54:44 +0000454 $table = '"' . str_replace('.', '"."', $table) . '"';
Derek Allardba0dd632007-03-07 12:10:58 +0000455 }
456
457 return $table;
458 }
459
460 // --------------------------------------------------------------------
461
462 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000463 * Protect Identifiers
464 *
465 * This function adds backticks if appropriate based on db type
466 *
467 * @access private
468 * @param mixed the item to escape
469 * @param boolean only affect the first word
470 * @return mixed the item with backticks
471 */
472 function _protect_identifiers($item, $first_word_only = FALSE)
473 {
474 if (is_array($item))
475 {
476 $escaped_array = array();
477
478 foreach($item as $k=>$v)
479 {
480 $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);
481 }
482
483 return $escaped_array;
484 }
485
486 // This function may get "item1 item2" as a string, and so
487 // we may need ""item1" "item2"" and not ""item1 item2""
Derek Allard61579382008-01-16 22:22:42 +0000488 if (ctype_alnum($item) === FALSE)
Derek Allard39b622d2008-01-16 21:10:09 +0000489 {
Derek Allard9b3e7b52008-02-04 23:20:34 +0000490 if (strpos($item, '.') !== FALSE)
491 {
492 $aliased_tables = implode(".",$this->ar_aliased_tables).'.';
493 $table_name = substr($item, 0, strpos($item, '.')+1);
494 $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;
495 }
496
Derek Allard39b622d2008-01-16 21:10:09 +0000497 // This function may get "field >= 1", and need it to return ""field" >= 1"
Derek Allard61579382008-01-16 22:22:42 +0000498 $lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';
Derek Allard39b622d2008-01-16 21:10:09 +0000499
Derek Allard61579382008-01-16 22:22:42 +0000500 $item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1"$2"$3', $item);
501 }
502 else
503 {
Derek Allard4acd7922008-01-26 19:33:59 +0000504 return "\"{$item}\"";
Derek Allard39b622d2008-01-16 21:10:09 +0000505 }
506
Derek Allard9a4d1da2008-02-25 14:18:38 +0000507 $exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');
Derek Allard39b622d2008-01-16 21:10:09 +0000508
509 foreach ($exceptions as $exception)
510 {
Derek Allard61579382008-01-16 22:22:42 +0000511
Derek Allard4acd7922008-01-26 19:33:59 +0000512 if (stristr($item, " \"{$exception}\" ") !== FALSE)
Derek Allard39b622d2008-01-16 21:10:09 +0000513 {
514 $item = preg_replace('/ "('.preg_quote($exception).')" /i', ' $1 ', $item);
515 }
516 }
Derek Allard39b622d2008-01-16 21:10:09 +0000517 return $item;
518 }
519
520 // --------------------------------------------------------------------
521
522 /**
Derek Jonesc6ad0232008-01-29 18:44:54 +0000523 * From Tables
524 *
525 * This function implicitly groups FROM tables so there is no confusion
526 * about operator precedence in harmony with SQL standards
527 *
528 * @access public
529 * @param type
530 * @return type
531 */
532 function _from_tables($tables)
533 {
Derek Jones0b59f272008-05-13 04:22:33 +0000534 if ( ! is_array($tables))
Derek Jonesc6ad0232008-01-29 18:44:54 +0000535 {
536 $tables = array($tables);
537 }
538
Derek Allard15648132008-02-10 21:46:18 +0000539 return implode(', ', $tables);
Derek Jonesc6ad0232008-01-29 18:44:54 +0000540 }
541
542 // --------------------------------------------------------------------
543
544 /**
Derek Allardba0dd632007-03-07 12:10:58 +0000545 * Insert statement
546 *
547 * Generates a platform-specific insert string from the supplied data
548 *
549 * @access public
550 * @param string the table name
551 * @param array the insert keys
552 * @param array the insert values
553 * @return string
554 */
555 function _insert($table, $keys, $values)
556 {
557 return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
558 }
559
560 // --------------------------------------------------------------------
561
562 /**
563 * Update statement
564 *
565 * Generates a platform-specific update string from the supplied data
566 *
567 * @access public
568 * @param string the table name
569 * @param array the update data
570 * @param array the where clause
Derek Allard39b622d2008-01-16 21:10:09 +0000571 * @param array the orderby clause
572 * @param array the limit clause
Derek Allardba0dd632007-03-07 12:10:58 +0000573 * @return string
574 */
Derek Allard39b622d2008-01-16 21:10:09 +0000575 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000576 {
577 foreach($values as $key => $val)
578 {
579 $valstr[] = $key." = ".$val;
580 }
Derek Allardda6d2402007-12-19 14:49:29 +0000581
Derek Jones0b59f272008-05-13 04:22:33 +0000582 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
Derek Allard39b622d2008-01-16 21:10:09 +0000583
584 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
Derek Allardba0dd632007-03-07 12:10:58 +0000585
Derek Allard32cf7eb2008-02-05 16:03:50 +0000586 $sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);
587 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
588 $sql .= $orderby.$limit;
589
590 return $sql;
Derek Allard39b622d2008-01-16 21:10:09 +0000591 }
592
593
594 // --------------------------------------------------------------------
595
596 /**
597 * Truncate statement
598 *
599 * Generates a platform-specific truncate string from the supplied data
600 * If the database does not support the truncate() command
601 * This function maps to "DELETE FROM table"
602 *
603 * @access public
604 * @param string the table name
605 * @return string
606 */
607 function _truncate($table)
608 {
609 return "TRUNCATE ".$this->_escape_table($table);
Derek Allardba0dd632007-03-07 12:10:58 +0000610 }
611
612 // --------------------------------------------------------------------
613
614 /**
615 * Delete statement
616 *
617 * Generates a platform-specific delete string from the supplied data
618 *
619 * @access public
620 * @param string the table name
621 * @param array the where clause
Derek Allard39b622d2008-01-16 21:10:09 +0000622 * @param string the limit clause
Derek Allardba0dd632007-03-07 12:10:58 +0000623 * @return string
624 */
Derek Allard39b622d2008-01-16 21:10:09 +0000625 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
Derek Allardba0dd632007-03-07 12:10:58 +0000626 {
Derek Allard39b622d2008-01-16 21:10:09 +0000627 $conditions = '';
628
Derek Jones0b59f272008-05-13 04:22:33 +0000629 if (count($where) > 0 OR count($like) > 0)
Derek Allard39b622d2008-01-16 21:10:09 +0000630 {
631 $conditions = "\nWHERE ";
632 $conditions .= implode("\n", $this->ar_where);
633
634 if (count($where) > 0 && count($like) > 0)
635 {
636 $conditions .= " AND ";
637 }
638 $conditions .= implode("\n", $like);
639 }
640
Derek Jones0b59f272008-05-13 04:22:33 +0000641 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
Derek Allarde77d77c2007-12-19 15:01:55 +0000642
Derek Allard39b622d2008-01-16 21:10:09 +0000643 return "DELETE FROM ".$table.$conditions.$limit;
Derek Allardba0dd632007-03-07 12:10:58 +0000644 }
645
646 // --------------------------------------------------------------------
Derek Allardba0dd632007-03-07 12:10:58 +0000647 /**
648 * Limit string
649 *
650 * Generates a platform-specific LIMIT clause
651 *
652 * @access public
653 * @param string the sql query string
654 * @param integer the number of rows to limit the query to
655 * @param integer the offset value
656 * @return string
657 */
658 function _limit($sql, $limit, $offset)
659 {
660 $sql .= "LIMIT ".$limit;
661
662 if ($offset > 0)
663 {
664 $sql .= " OFFSET ".$offset;
665 }
666
667 return $sql;
668 }
669
670 // --------------------------------------------------------------------
671
672 /**
673 * Close DB Connection
674 *
675 * @access public
676 * @param resource
677 * @return void
678 */
679 function _close($conn_id)
680 {
681 @pg_close($conn_id);
682 }
683
684
685}
686
Derek Jones0b59f272008-05-13 04:22:33 +0000687
688/* End of file postgre_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000689/* Location: ./system/database/drivers/postgre/postgre_driver.php */