blob: 3adc5f5ef68d75bb8610e817ee8f5de8e2afd752 [file] [log] [blame]
Timothy Warren80ab8162011-08-22 18:26:12 -04001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 5.1.6 or newer
6 *
7 * @package CodeIgniter
8 * @author ExpressionEngine Dev Team
9 * @copyright Copyright (c) 2008 - 2011, 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 * ODBC 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_pdo_driver extends CI_DB {
32
33 var $dbdriver = 'pdo';
34
35 // the character used to excape - not necessary for PDO
36 var $_escape_char = '';
37
38 // clause and character used for LIKE escape sequences
39 var $_like_escape_str = " {escape '%s'} ";
40 var $_like_escape_chr = '!';
41
42 /**
43 * The syntax to count rows is slightly different across different
44 * database engines, so this string appears in each driver and is
45 * used for the count_all() and count_all_results() functions.
46 */
47 var $_count_string = "SELECT COUNT(*) AS ";
48 var $_random_keyword;
49
50
51 function CI_DB_pdo_driver($params)
52 {
53 parent::CI_DB($params);
Timothy Warrenab347582011-08-23 12:29:29 -040054
55 $this->hostname = $this->hostname . ";dbname=".$this->database;
56 $this->trans_enabled = FALSE;
Timothy Warren80ab8162011-08-22 18:26:12 -040057
58 $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
59 }
60
61 /**
62 * Non-persistent database connection
63 *
64 * @access private called by the base class
65 * @return resource
66 */
67 function db_connect()
68 {
Timothy Warrenab347582011-08-23 12:29:29 -040069 return new PDO($this->hostname,$this->username,$this->password, array(
70 PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT
Timothy Warren80ab8162011-08-22 18:26:12 -040071 ));
72 }
73
74 // --------------------------------------------------------------------
75
76 /**
77 * Persistent database connection
78 *
79 * @access private called by the base class
80 * @return resource
81 */
82 function db_pconnect()
83 {
Timothy Warrenab347582011-08-23 12:29:29 -040084 return new PDO($this->hostname,$this->username,$this->password, array(
85 PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
86 PDO::ATTR_PERSISTENT => true
Timothy Warren80ab8162011-08-22 18:26:12 -040087 ));
88 }
89
90 // --------------------------------------------------------------------
91
92 /**
93 * Reconnect
94 *
95 * Keep / reestablish the db connection if no queries have been
96 * sent for a length of time exceeding the server's idle timeout
97 *
98 * @access public
99 * @return void
100 */
101 function reconnect()
102 {
103 // not implemented in pdo
104 }
105
106 // --------------------------------------------------------------------
107
108 /**
109 * Select the database
110 *
111 * @access private called by the base class
112 * @return resource
113 */
114 function db_select()
115 {
116 // Not needed for PDO
117 return TRUE;
118 }
119
120 // --------------------------------------------------------------------
121
122 /**
123 * Set client character set
124 *
125 * @access public
126 * @param string
127 * @param string
128 * @return resource
129 */
130 function db_set_charset($charset, $collation)
131 {
132 // @todo - add support if needed
133 return TRUE;
134 }
135
136 // --------------------------------------------------------------------
137
138 /**
139 * Version number query string
140 *
141 * @access public
142 * @return string
143 */
144 function _version()
145 {
146 return "SELECT version() AS ver";
147 }
148
149 // --------------------------------------------------------------------
150
151 /**
152 * Execute the query
153 *
154 * @access private called by the base class
155 * @param string an SQL query
156 * @return resource
157 */
158 function _execute($sql)
159 {
160 $sql = $this->_prep_query($sql);
Timothy Warrenab347582011-08-23 12:29:29 -0400161 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400162 }
163
164 // --------------------------------------------------------------------
165
166 /**
167 * Prep the query
168 *
169 * If needed, each database adapter can prep the query string
170 *
171 * @access private called by execute()
172 * @param string an SQL query
173 * @return string
174 */
175 function _prep_query($sql)
176 {
177 return $sql;
178 }
179
180 // --------------------------------------------------------------------
181
182 /**
183 * Begin Transaction
184 *
185 * @access public
186 * @return bool
187 */
188 function trans_begin($test_mode = FALSE)
189 {
190 if ( ! $this->trans_enabled)
191 {
192 return TRUE;
193 }
194
195 // When transactions are nested we only begin/commit/rollback the outermost ones
196 if ($this->_trans_depth > 0)
197 {
198 return TRUE;
199 }
200
201 // Reset the transaction failure flag.
202 // If the $test_mode flag is set to TRUE transactions will be rolled back
203 // even if the queries produce a successful result.
204 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
205
Timothy Warrenab347582011-08-23 12:29:29 -0400206 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400207 }
208
209 // --------------------------------------------------------------------
210
211 /**
212 * Commit Transaction
213 *
214 * @access public
215 * @return bool
216 */
217 function trans_commit()
218 {
219 if ( ! $this->trans_enabled)
220 {
221 return TRUE;
222 }
223
224 // When transactions are nested we only begin/commit/rollback the outermost ones
225 if ($this->_trans_depth > 0)
226 {
227 return TRUE;
228 }
229
Timothy Warrenab347582011-08-23 12:29:29 -0400230 $ret = $this->conn->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400231 return $ret;
232 }
233
234 // --------------------------------------------------------------------
235
236 /**
237 * Rollback Transaction
238 *
239 * @access public
240 * @return bool
241 */
242 function trans_rollback()
243 {
244 if ( ! $this->trans_enabled)
245 {
246 return TRUE;
247 }
248
249 // When transactions are nested we only begin/commit/rollback the outermost ones
250 if ($this->_trans_depth > 0)
251 {
252 return TRUE;
253 }
254
Timothy Warrenab347582011-08-23 12:29:29 -0400255 $ret = $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400256 return $ret;
257 }
258
259 // --------------------------------------------------------------------
260
261 /**
262 * Escape String
263 *
264 * @access public
265 * @param string
266 * @param bool whether or not the string will be used in a LIKE condition
267 * @return string
268 */
269 function escape_str($str, $like = FALSE)
270 {
271 if (is_array($str))
272 {
273 foreach ($str as $key => $val)
274 {
275 $str[$key] = $this->escape_str($val, $like);
276 }
277
278 return $str;
279 }
280
281 // PDO doesn't require escaping
282 $str = remove_invisible_characters($str);
283
284 // escape LIKE condition wildcards
285 if ($like === TRUE)
286 {
287 $str = str_replace( array('%', '_', $this->_like_escape_chr),
288 array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
289 $str);
290 }
291
292 return $str;
293 }
294
295 // --------------------------------------------------------------------
296
297 /**
298 * Affected Rows
299 *
300 * @access public
301 * @return integer
302 */
303 function affected_rows()
304 {
305 return @pdo_num_rows($this->conn_id);
306 }
307
308 // --------------------------------------------------------------------
309
310 /**
311 * Insert ID
312 *
313 * @access public
314 * @return integer
315 */
316 function insert_id()
317 {
Timothy Warrenab347582011-08-23 12:29:29 -0400318 return $this->conn_id->lastInsertId();
Timothy Warren80ab8162011-08-22 18:26:12 -0400319 }
320
321 // --------------------------------------------------------------------
322
323 /**
324 * "Count All" query
325 *
326 * Generates a platform-specific query string that counts all records in
327 * the specified database
328 *
329 * @access public
330 * @param string
331 * @return string
332 */
333 function count_all($table = '')
334 {
335 if ($table == '')
336 {
337 return 0;
338 }
339
340 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
341
342 if ($query->num_rows() == 0)
343 {
344 return 0;
345 }
346
347 $row = $query->row();
348 $this->_reset_select();
349 return (int) $row->numrows;
350 }
351
352 // --------------------------------------------------------------------
353
354 /**
355 * Show table query
356 *
357 * Generates a platform-specific query string so that the table names can be fetched
358 *
359 * @access private
360 * @param boolean
361 * @return string
362 */
363 function _list_tables($prefix_limit = FALSE)
364 {
365 $sql = "SHOW TABLES FROM `".$this->database."`";
366
367 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
368 {
369 //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
370 return FALSE; // not currently supported
371 }
372
373 return $sql;
374 }
375
376 // --------------------------------------------------------------------
377
378 /**
379 * Show column query
380 *
381 * Generates a platform-specific query string so that the column names can be fetched
382 *
383 * @access public
384 * @param string the table name
385 * @return string
386 */
387 function _list_columns($table = '')
388 {
389 return "SHOW COLUMNS FROM ".$table;
390 }
391
392 // --------------------------------------------------------------------
393
394 /**
395 * Field data query
396 *
397 * Generates a platform-specific query so that the column data can be retrieved
398 *
399 * @access public
400 * @param string the table name
401 * @return object
402 */
403 function _field_data($table)
404 {
405 return "SELECT TOP 1 FROM ".$table;
406 }
407
408 // --------------------------------------------------------------------
409
410 /**
411 * The error message string
412 *
413 * @access private
414 * @return string
415 */
416 function _error_message()
417 {
Timothy Warrenab347582011-08-23 12:29:29 -0400418 $error_array = $this->conn_id->errorInfo();
419 return $error_array[2];
Timothy Warren80ab8162011-08-22 18:26:12 -0400420 }
421
422 // --------------------------------------------------------------------
423
424 /**
425 * The error message number
426 *
427 * @access private
428 * @return integer
429 */
430 function _error_number()
431 {
Timothy Warrenab347582011-08-23 12:29:29 -0400432 return $this->conn_id->errorCode();
Timothy Warren80ab8162011-08-22 18:26:12 -0400433 }
434
435 // --------------------------------------------------------------------
436
437 /**
438 * Escape the SQL Identifiers
439 *
440 * This function escapes column and table names
441 *
442 * @access private
443 * @param string
444 * @return string
445 */
446 function _escape_identifiers($item)
447 {
448 if ($this->_escape_char == '')
449 {
450 return $item;
451 }
452
453 foreach ($this->_reserved_identifiers as $id)
454 {
455 if (strpos($item, '.'.$id) !== FALSE)
456 {
457 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
458
459 // remove duplicates if the user already included the escape
460 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
461 }
462 }
463
464 if (strpos($item, '.') !== FALSE)
465 {
466 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
467 }
468 else
469 {
470 $str = $this->_escape_char.$item.$this->_escape_char;
471 }
472
473 // remove duplicates if the user already included the escape
474 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
475 }
476
477 // --------------------------------------------------------------------
478
479 /**
480 * From Tables
481 *
482 * This function implicitly groups FROM tables so there is no confusion
483 * about operator precedence in harmony with SQL standards
484 *
485 * @access public
486 * @param type
487 * @return type
488 */
489 function _from_tables($tables)
490 {
491 if ( ! is_array($tables))
492 {
493 $tables = array($tables);
494 }
495
Timothy Warrenab347582011-08-23 12:29:29 -0400496 return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')';
Timothy Warren80ab8162011-08-22 18:26:12 -0400497 }
498
499 // --------------------------------------------------------------------
500
501 /**
502 * Insert statement
503 *
504 * Generates a platform-specific insert string from the supplied data
505 *
506 * @access public
507 * @param string the table name
508 * @param array the insert keys
509 * @param array the insert values
510 * @return string
511 */
512 function _insert($table, $keys, $values)
513 {
514 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
515 }
516
517 // --------------------------------------------------------------------
518
519 /**
520 * Update statement
521 *
522 * Generates a platform-specific update string from the supplied data
523 *
524 * @access public
525 * @param string the table name
526 * @param array the update data
527 * @param array the where clause
528 * @param array the orderby clause
529 * @param array the limit clause
530 * @return string
531 */
532 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
533 {
534 foreach ($values as $key => $val)
535 {
536 $valstr[] = $key." = ".$val;
537 }
538
539 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
540
541 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
542
543 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
544
545 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
546
547 $sql .= $orderby.$limit;
548
549 return $sql;
550 }
551
552
553 // --------------------------------------------------------------------
554
555 /**
556 * Truncate statement
557 *
558 * Generates a platform-specific truncate string from the supplied data
559 * If the database does not support the truncate() command
560 * This function maps to "DELETE FROM table"
561 *
562 * @access public
563 * @param string the table name
564 * @return string
565 */
566 function _truncate($table)
567 {
568 return $this->_delete($table);
569 }
570
571 // --------------------------------------------------------------------
572
573 /**
574 * Delete statement
575 *
576 * Generates a platform-specific delete string from the supplied data
577 *
578 * @access public
579 * @param string the table name
580 * @param array the where clause
581 * @param string the limit clause
582 * @return string
583 */
584 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
585 {
586 $conditions = '';
587
588 if (count($where) > 0 OR count($like) > 0)
589 {
590 $conditions = "\nWHERE ";
591 $conditions .= implode("\n", $this->ar_where);
592
593 if (count($where) > 0 && count($like) > 0)
594 {
595 $conditions .= " AND ";
596 }
597 $conditions .= implode("\n", $like);
598 }
599
600 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
601
602 return "DELETE FROM ".$table.$conditions.$limit;
603 }
604
605 // --------------------------------------------------------------------
606
607 /**
608 * Limit string
609 *
610 * Generates a platform-specific LIMIT clause
611 *
612 * @access public
613 * @param string the sql query string
614 * @param integer the number of rows to limit the query to
615 * @param integer the offset value
616 * @return string
617 */
618 function _limit($sql, $limit, $offset)
619 {
620 // Does PDO doesn't use the LIMIT clause?
621 return $sql;
622 }
623
624 // --------------------------------------------------------------------
625
626 /**
627 * Close DB Connection
628 *
629 * @access public
630 * @param resource
631 * @return void
632 */
633 function _close($conn_id)
634 {
635 @pdo_close($conn_id);
636 }
637
638
639}
640
641
642
643/* End of file pdo_driver.php */
644/* Location: ./system/database/drivers/pdo/pdo_driver.php */