blob: 4bc5b7d940044166f34f350a11fa754e97ae8c81 [file] [log] [blame]
Derek Allard2067d1a2008-11-13 22:59:24 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author ExpressionEngine Dev Team
9 * @copyright Copyright (c) 2008, EllisLab, Inc.
10 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
12 * @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
28 * @author ExpressionEngine Dev Team
29 * @link http://codeigniter.com/user_guide/database/
30 */
31class CI_DB_postgre_driver extends CI_DB {
32
33 var $dbdriver = 'postgre';
34
35 var $_escape_char = '"';
36
Derek Jonese4ed5832009-02-20 21:44:59 +000037 // clause and character used for LIKE escape sequences
38 var $_like_escape_str = " ESCAPE '%s' ";
39 var $_like_escape_chr = '!';
40
Derek Allard2067d1a2008-11-13 22:59:24 +000041 /**
42 * The syntax to count rows is slightly different across different
43 * database engines, so this string appears in each driver and is
44 * used for the count_all() and count_all_results() functions.
45 */
46 var $_count_string = "SELECT COUNT(*) AS ";
47 var $_random_keyword = ' RANDOM()'; // database specific random keyword
48
49 /**
50 * Connection String
51 *
52 * @access private
53 * @return string
54 */
55 function _connect_string()
56 {
57 $components = array(
58 'hostname' => 'host',
59 'port' => 'port',
60 'database' => 'dbname',
61 'username' => 'user',
62 'password' => 'password'
63 );
64
65 $connect_string = "";
66 foreach ($components as $key => $val)
67 {
68 if (isset($this->$key) && $this->$key != '')
69 {
70 $connect_string .= " $val=".$this->$key;
71 }
72 }
73 return trim($connect_string);
74 }
75
76 // --------------------------------------------------------------------
77
78 /**
79 * Non-persistent database connection
80 *
81 * @access private called by the base class
82 * @return resource
83 */
84 function db_connect()
85 {
86 return @pg_connect($this->_connect_string());
87 }
88
89 // --------------------------------------------------------------------
90
91 /**
92 * Persistent database connection
93 *
94 * @access private called by the base class
95 * @return resource
96 */
97 function db_pconnect()
98 {
99 return @pg_pconnect($this->_connect_string());
100 }
101
102 // --------------------------------------------------------------------
103
104 /**
105 * Select the database
106 *
107 * @access private called by the base class
108 * @return resource
109 */
110 function db_select()
111 {
112 // Not needed for Postgre so we'll return TRUE
113 return TRUE;
114 }
115
116 // --------------------------------------------------------------------
117
118 /**
119 * Set client character set
120 *
121 * @access public
122 * @param string
123 * @param string
124 * @return resource
125 */
126 function db_set_charset($charset, $collation)
127 {
128 // @todo - add support if needed
129 return TRUE;
130 }
131
132 // --------------------------------------------------------------------
133
134 /**
135 * Version number query string
136 *
137 * @access public
138 * @return string
139 */
140 function _version()
141 {
142 return "SELECT version() AS ver";
143 }
144
145 // --------------------------------------------------------------------
146
147 /**
148 * Execute the query
149 *
150 * @access private called by the base class
151 * @param string an SQL query
152 * @return resource
153 */
154 function _execute($sql)
155 {
156 $sql = $this->_prep_query($sql);
157 return @pg_query($this->conn_id, $sql);
158 }
159
160 // --------------------------------------------------------------------
161
162 /**
163 * Prep the query
164 *
165 * If needed, each database adapter can prep the query string
166 *
167 * @access private called by execute()
168 * @param string an SQL query
169 * @return string
170 */
171 function _prep_query($sql)
172 {
173 return $sql;
174 }
175
176 // --------------------------------------------------------------------
177
178 /**
179 * Begin Transaction
180 *
181 * @access public
182 * @return bool
183 */
184 function trans_begin($test_mode = FALSE)
185 {
186 if ( ! $this->trans_enabled)
187 {
188 return TRUE;
189 }
190
191 // When transactions are nested we only begin/commit/rollback the outermost ones
192 if ($this->_trans_depth > 0)
193 {
194 return TRUE;
195 }
196
197 // Reset the transaction failure flag.
198 // If the $test_mode flag is set to TRUE transactions will be rolled back
199 // even if the queries produce a successful result.
200 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
201
202 return @pg_exec($this->conn_id, "begin");
203 }
204
205 // --------------------------------------------------------------------
206
207 /**
208 * Commit Transaction
209 *
210 * @access public
211 * @return bool
212 */
213 function trans_commit()
214 {
215 if ( ! $this->trans_enabled)
216 {
217 return TRUE;
218 }
219
220 // When transactions are nested we only begin/commit/rollback the outermost ones
221 if ($this->_trans_depth > 0)
222 {
223 return TRUE;
224 }
225
226 return @pg_exec($this->conn_id, "commit");
227 }
228
229 // --------------------------------------------------------------------
230
231 /**
232 * Rollback Transaction
233 *
234 * @access public
235 * @return bool
236 */
237 function trans_rollback()
238 {
239 if ( ! $this->trans_enabled)
240 {
241 return TRUE;
242 }
243
244 // When transactions are nested we only begin/commit/rollback the outermost ones
245 if ($this->_trans_depth > 0)
246 {
247 return TRUE;
248 }
249
250 return @pg_exec($this->conn_id, "rollback");
251 }
252
253 // --------------------------------------------------------------------
254
255 /**
256 * Escape String
257 *
258 * @access public
259 * @param string
Derek Jonese4ed5832009-02-20 21:44:59 +0000260 * @param bool whether or not the string will be used in a LIKE condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000261 * @return string
262 */
Derek Jonese4ed5832009-02-20 21:44:59 +0000263 function escape_str($str, $like = FALSE)
264 {
265 if (is_array($str))
266 {
267 foreach($str as $key => $val)
268 {
269 $str[$key] = $this->escape_str($val, $like);
270 }
271
272 return $str;
273 }
274
275 $str = pg_escape_string($str);
276
277 // escape LIKE condition wildcards
278 if ($like === TRUE)
279 {
280 $str = str_replace( array('%', '_', $this->_like_escape_chr),
281 array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
282 $str);
283 }
284
285 return $str;
Derek Allard2067d1a2008-11-13 22:59:24 +0000286 }
287
288 // --------------------------------------------------------------------
289
290 /**
291 * Affected Rows
292 *
293 * @access public
294 * @return integer
295 */
296 function affected_rows()
297 {
298 return @pg_affected_rows($this->result_id);
299 }
300
301 // --------------------------------------------------------------------
302
303 /**
304 * Insert ID
305 *
306 * @access public
307 * @return integer
308 */
309 function insert_id()
310 {
311 $v = $this->_version();
312 $v = $v['server'];
313
314 $table = func_num_args() > 0 ? func_get_arg(0) : null;
315 $column = func_num_args() > 1 ? func_get_arg(1) : null;
316
317 if ($table == null && $v >= '8.1')
318 {
319 $sql='SELECT LASTVAL() as ins_id';
320 }
321 elseif ($table != null && $column != null && $v >= '8.0')
322 {
323 $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column);
324 $query = $this->query($sql);
325 $row = $query->row();
326 $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq);
327 }
328 elseif ($table != null)
329 {
330 // seq_name passed in table parameter
331 $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table);
332 }
333 else
334 {
335 return pg_last_oid($this->result_id);
336 }
337 $query = $this->query($sql);
338 $row = $query->row();
339 return $row->ins_id;
340 }
341
342 // --------------------------------------------------------------------
343
344 /**
345 * "Count All" query
346 *
347 * Generates a platform-specific query string that counts all records in
348 * the specified database
349 *
350 * @access public
351 * @param string
352 * @return string
353 */
354 function count_all($table = '')
355 {
356 if ($table == '')
Derek Allarde37ab382009-02-03 16:13:57 +0000357 {
358 return 0;
359 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000360
Derek Allarde37ab382009-02-03 16:13:57 +0000361 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
362
Derek Allard2067d1a2008-11-13 22:59:24 +0000363 if ($query->num_rows() == 0)
Derek Allarde37ab382009-02-03 16:13:57 +0000364 {
365 return 0;
366 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000367
368 $row = $query->row();
Derek Allarde37ab382009-02-03 16:13:57 +0000369 return (int) $row->numrows;
Derek Allard2067d1a2008-11-13 22:59:24 +0000370 }
371
372 // --------------------------------------------------------------------
373
374 /**
375 * Show table query
376 *
377 * Generates a platform-specific query string so that the table names can be fetched
378 *
379 * @access private
380 * @param boolean
381 * @return string
382 */
383 function _list_tables($prefix_limit = FALSE)
384 {
385 $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'";
386
387 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
388 {
Derek Jones3c11b6f2009-02-20 22:36:27 +0000389 $sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_char);
Derek Allard2067d1a2008-11-13 22:59:24 +0000390 }
391
392 return $sql;
393 }
394
395 // --------------------------------------------------------------------
396
397 /**
398 * Show column query
399 *
400 * Generates a platform-specific query string so that the column names can be fetched
401 *
402 * @access public
403 * @param string the table name
404 * @return string
405 */
406 function _list_columns($table = '')
407 {
408 return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$table."'";
409 }
410
411 // --------------------------------------------------------------------
412
413 /**
414 * Field data query
415 *
416 * Generates a platform-specific query so that the column data can be retrieved
417 *
418 * @access public
419 * @param string the table name
420 * @return object
421 */
422 function _field_data($table)
423 {
424 return "SELECT * FROM ".$table." LIMIT 1";
425 }
426
427 // --------------------------------------------------------------------
428
429 /**
430 * The error message string
431 *
432 * @access private
433 * @return string
434 */
435 function _error_message()
436 {
437 return pg_last_error($this->conn_id);
438 }
439
440 // --------------------------------------------------------------------
441
442 /**
443 * The error message number
444 *
445 * @access private
446 * @return integer
447 */
448 function _error_number()
449 {
450 return '';
451 }
452
453 // --------------------------------------------------------------------
454
455 /**
456 * Escape the SQL Identifiers
457 *
458 * This function escapes column and table names
459 *
460 * @access private
461 * @param string
462 * @return string
463 */
464 function _escape_identifiers($item)
465 {
466 if ($this->_escape_char == '')
467 {
468 return $item;
469 }
470
471 foreach ($this->_reserved_identifiers as $id)
472 {
473 if (strpos($item, '.'.$id) !== FALSE)
474 {
475 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
476
477 // remove duplicates if the user already included the escape
478 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
479 }
480 }
481
482 if (strpos($item, '.') !== FALSE)
483 {
484 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
485 }
486 else
487 {
488 $str = $this->_escape_char.$item.$this->_escape_char;
489 }
490
491 // remove duplicates if the user already included the escape
492 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
493 }
494
495 // --------------------------------------------------------------------
496
497 /**
498 * From Tables
499 *
500 * This function implicitly groups FROM tables so there is no confusion
501 * about operator precedence in harmony with SQL standards
502 *
503 * @access public
504 * @param type
505 * @return type
506 */
507 function _from_tables($tables)
508 {
509 if ( ! is_array($tables))
510 {
511 $tables = array($tables);
512 }
513
514 return implode(', ', $tables);
515 }
516
517 // --------------------------------------------------------------------
518
519 /**
520 * Insert statement
521 *
522 * Generates a platform-specific insert string from the supplied data
523 *
524 * @access public
525 * @param string the table name
526 * @param array the insert keys
527 * @param array the insert values
528 * @return string
529 */
530 function _insert($table, $keys, $values)
531 {
532 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
533 }
534
535 // --------------------------------------------------------------------
536
537 /**
538 * Update statement
539 *
540 * Generates a platform-specific update string from the supplied data
541 *
542 * @access public
543 * @param string the table name
544 * @param array the update data
545 * @param array the where clause
546 * @param array the orderby clause
547 * @param array the limit clause
548 * @return string
549 */
550 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
551 {
552 foreach($values as $key => $val)
553 {
554 $valstr[] = $key." = ".$val;
555 }
556
557 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
558
559 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
560
561 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
562
563 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
564
565 $sql .= $orderby.$limit;
566
567 return $sql;
568 }
569
570 // --------------------------------------------------------------------
571
572 /**
573 * Truncate statement
574 *
575 * Generates a platform-specific truncate string from the supplied data
576 * If the database does not support the truncate() command
577 * This function maps to "DELETE FROM table"
578 *
579 * @access public
580 * @param string the table name
581 * @return string
582 */
583 function _truncate($table)
584 {
585 return "TRUNCATE ".$table;
586 }
587
588 // --------------------------------------------------------------------
589
590 /**
591 * Delete statement
592 *
593 * Generates a platform-specific delete string from the supplied data
594 *
595 * @access public
596 * @param string the table name
597 * @param array the where clause
598 * @param string the limit clause
599 * @return string
600 */
601 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
602 {
603 $conditions = '';
604
605 if (count($where) > 0 OR count($like) > 0)
606 {
607 $conditions = "\nWHERE ";
608 $conditions .= implode("\n", $this->ar_where);
609
610 if (count($where) > 0 && count($like) > 0)
611 {
612 $conditions .= " AND ";
613 }
614 $conditions .= implode("\n", $like);
615 }
616
617 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
618
619 return "DELETE FROM ".$table.$conditions.$limit;
620 }
621
622 // --------------------------------------------------------------------
623 /**
624 * Limit string
625 *
626 * Generates a platform-specific LIMIT clause
627 *
628 * @access public
629 * @param string the sql query string
630 * @param integer the number of rows to limit the query to
631 * @param integer the offset value
632 * @return string
633 */
634 function _limit($sql, $limit, $offset)
635 {
636 $sql .= "LIMIT ".$limit;
637
638 if ($offset > 0)
639 {
640 $sql .= " OFFSET ".$offset;
641 }
642
643 return $sql;
644 }
645
646 // --------------------------------------------------------------------
647
648 /**
649 * Close DB Connection
650 *
651 * @access public
652 * @param resource
653 * @return void
654 */
655 function _close($conn_id)
656 {
657 @pg_close($conn_id);
658 }
659
660
661}
662
663
664/* End of file postgre_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000665/* Location: ./system/database/drivers/postgre/postgre_driver.php */