blob: 1b3da7a6be6dd43f3562905cfe0e6eaa33057c68 [file] [log] [blame]
Derek Jones0b59f272008-05-13 04:22:33 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allardd2df9bc2007-04-15 17:41:17 +00002/**
3 * CodeIgniter
4 *
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 Allardd2df9bc2007-04-15 17:41:17 +000012 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * MySQLi Database Adapter Class - MySQLi only works with PHP 5
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 Allardd2df9bc2007-04-15 17:41:17 +000030 */
31class CI_DB_mysqli_driver extends CI_DB {
32
Rick Ellis5aa8c602008-10-07 01:24:07 +000033 var $dbdriver = 'mysqli';
Rick Ellis605a07a2008-10-17 04:07:54 +000034
35 // The character used for escaping
36 var $_escape_char = '`';
Rick Ellis5aa8c602008-10-07 01:24:07 +000037
Derek Allardd2df9bc2007-04-15 17:41:17 +000038 /**
Derek Allard694b5b82007-12-18 15:58:03 +000039 * The syntax to count rows is slightly different across different
40 * database engines, so this string appears in each driver and is
41 * used for the count_all() and count_all_results() functions.
42 */
Derek Allard39b622d2008-01-16 21:10:09 +000043 var $_count_string = "SELECT COUNT(*) AS ";
Derek Allard6ddb5a12007-12-18 17:22:50 +000044 var $_random_keyword = ' RAND()'; // database specific random keyword
45
Derek Allard694b5b82007-12-18 15:58:03 +000046 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +000047 * Whether to use the MySQL "delete hack" which allows the number
48 * of affected rows to be shown. Uses a preg_replace when enabled,
49 * adding a bit more processing to all queries.
50 */
51 var $delete_hack = TRUE;
52
53 // --------------------------------------------------------------------
54
55 /**
56 * Non-persistent database connection
57 *
58 * @access private called by the base class
59 * @return resource
60 */
61 function db_connect()
62 {
Derek Jones4ba802d2008-10-24 16:43:02 +000063 if ($this->port != '')
64 {
65 return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port);
66 }
67 else
68 {
69 return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
70 }
71
Derek Allardd2df9bc2007-04-15 17:41:17 +000072 }
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 {
84 return $this->db_connect();
85 }
86
87 // --------------------------------------------------------------------
88
89 /**
90 * Select the database
91 *
92 * @access private called by the base class
93 * @return resource
94 */
95 function db_select()
96 {
97 return @mysqli_select_db($this->conn_id, $this->database);
98 }
99
100 // --------------------------------------------------------------------
101
102 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000103 * Set client character set
104 *
Rick Ellis605a07a2008-10-17 04:07:54 +0000105 * @access private
Derek Allard39b622d2008-01-16 21:10:09 +0000106 * @param string
107 * @param string
108 * @return resource
109 */
Rick Ellis605a07a2008-10-17 04:07:54 +0000110 function _db_set_charset($charset, $collation)
Derek Allard39b622d2008-01-16 21:10:09 +0000111 {
Derek Jonesb1f90db2008-02-13 05:22:38 +0000112 return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
Derek Allard39b622d2008-01-16 21:10:09 +0000113 }
114
115 // --------------------------------------------------------------------
116
117 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000118 * Version number query string
119 *
120 * @access public
121 * @return string
122 */
123 function _version()
124 {
125 return "SELECT version() AS ver";
126 }
127
128 // --------------------------------------------------------------------
129
130 /**
131 * Execute the query
132 *
133 * @access private called by the base class
134 * @param string an SQL query
135 * @return resource
136 */
137 function _execute($sql)
138 {
139 $sql = $this->_prep_query($sql);
140 $result = @mysqli_query($this->conn_id, $sql);
141 return $result;
142 }
143
144 // --------------------------------------------------------------------
145
146 /**
147 * Prep the query
148 *
149 * If needed, each database adapter can prep the query string
150 *
151 * @access private called by execute()
152 * @param string an SQL query
153 * @return string
154 */
155 function _prep_query($sql)
156 {
157 // "DELETE FROM TABLE" returns 0 affected rows This hack modifies
158 // the query so that it returns the number of affected rows
159 if ($this->delete_hack === TRUE)
160 {
161 if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
162 {
163 $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql);
164 }
165 }
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 Allardd2df9bc2007-04-15 17:41:17 +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 $this->simple_query('SET AUTOCOMMIT=0');
197 $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
198 return TRUE;
199 }
200
201 // --------------------------------------------------------------------
202
203 /**
204 * Commit Transaction
205 *
206 * @access public
207 * @return bool
208 */
209 function trans_commit()
210 {
Derek Jones0b59f272008-05-13 04:22:33 +0000211 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000212 {
213 return TRUE;
214 }
215
216 // When transactions are nested we only begin/commit/rollback the outermost ones
217 if ($this->_trans_depth > 0)
218 {
219 return TRUE;
220 }
221
222 $this->simple_query('COMMIT');
223 $this->simple_query('SET AUTOCOMMIT=1');
224 return TRUE;
225 }
226
227 // --------------------------------------------------------------------
228
229 /**
230 * Rollback Transaction
231 *
232 * @access public
233 * @return bool
234 */
235 function trans_rollback()
236 {
Derek Jones0b59f272008-05-13 04:22:33 +0000237 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000238 {
239 return TRUE;
240 }
241
242 // When transactions are nested we only begin/commit/rollback the outermost ones
243 if ($this->_trans_depth > 0)
244 {
245 return TRUE;
246 }
247
248 $this->simple_query('ROLLBACK');
249 $this->simple_query('SET AUTOCOMMIT=1');
250 return TRUE;
251 }
252
253 // --------------------------------------------------------------------
254
255 /**
256 * Escape String
257 *
258 * @access public
259 * @param string
260 * @return string
261 */
262 function escape_str($str)
Derek Allard694b5b82007-12-18 15:58:03 +0000263 {
Derek Jonesd33972b2008-02-13 04:16:27 +0000264 if (function_exists('mysqli_real_escape_string') AND is_object($this->conn_id))
Derek Allard694b5b82007-12-18 15:58:03 +0000265 {
266 return mysqli_real_escape_string($this->conn_id, $str);
267 }
268 elseif (function_exists('mysql_escape_string'))
269 {
270 return mysql_escape_string($str);
271 }
272 else
273 {
274 return addslashes($str);
275 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000276 }
277
278 // --------------------------------------------------------------------
279
280 /**
281 * Affected Rows
282 *
283 * @access public
284 * @return integer
285 */
286 function affected_rows()
287 {
288 return @mysqli_affected_rows($this->conn_id);
289 }
290
291 // --------------------------------------------------------------------
292
293 /**
294 * Insert ID
295 *
296 * @access public
297 * @return integer
298 */
299 function insert_id()
300 {
301 return @mysqli_insert_id($this->conn_id);
302 }
303
304 // --------------------------------------------------------------------
305
306 /**
307 * "Count All" query
308 *
309 * Generates a platform-specific query string that counts all records in
310 * the specified database
311 *
312 * @access public
313 * @param string
314 * @return string
315 */
316 function count_all($table = '')
317 {
318 if ($table == '')
319 return '0';
Rick Ellis605a07a2008-10-17 04:07:54 +0000320
321 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
Derek Allardd2df9bc2007-04-15 17:41:17 +0000322
323 if ($query->num_rows() == 0)
324 return '0';
325
326 $row = $query->row();
327 return $row->numrows;
328 }
329
330 // --------------------------------------------------------------------
331
332 /**
333 * List table query
334 *
335 * Generates a platform-specific query string so that the table names can be fetched
336 *
337 * @access private
Derek Allard39b622d2008-01-16 21:10:09 +0000338 * @param boolean
Derek Allardd2df9bc2007-04-15 17:41:17 +0000339 * @return string
340 */
Derek Allard694b5b82007-12-18 15:58:03 +0000341 function _list_tables($prefix_limit = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000342 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000343 $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;
Derek Allard694b5b82007-12-18 15:58:03 +0000344
Derek Allard39b622d2008-01-16 21:10:09 +0000345 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
Derek Allard694b5b82007-12-18 15:58:03 +0000346 {
Derek Allard39b622d2008-01-16 21:10:09 +0000347 $sql .= " LIKE '".$this->dbprefix."%'";
Derek Allard694b5b82007-12-18 15:58:03 +0000348 }
349
350 return $sql;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000351 }
352
353 // --------------------------------------------------------------------
354
355 /**
356 * Show column query
357 *
358 * Generates a platform-specific query string so that the column names can be fetched
359 *
360 * @access public
361 * @param string the table name
362 * @return string
363 */
364 function _list_columns($table = '')
365 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000366 return "SHOW COLUMNS FROM ".$table;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000367 }
368
369 // --------------------------------------------------------------------
370
371 /**
372 * Field data query
373 *
374 * Generates a platform-specific query so that the column data can be retrieved
375 *
376 * @access public
377 * @param string the table name
378 * @return object
379 */
380 function _field_data($table)
381 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000382 return "SELECT * FROM ".$table." LIMIT 1";
Derek Allardd2df9bc2007-04-15 17:41:17 +0000383 }
384
385 // --------------------------------------------------------------------
386
387 /**
388 * The error message string
389 *
390 * @access private
391 * @return string
392 */
393 function _error_message()
394 {
395 return mysqli_error($this->conn_id);
396 }
397
398 // --------------------------------------------------------------------
399
400 /**
401 * The error message number
402 *
403 * @access private
404 * @return integer
405 */
406 function _error_number()
407 {
408 return mysqli_errno($this->conn_id);
409 }
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000410
411 // --------------------------------------------------------------------
412
413 /**
Rick Ellis605a07a2008-10-17 04:07:54 +0000414 * Escape the SQL Identifiers
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000415 *
Rick Ellis605a07a2008-10-17 04:07:54 +0000416 * This function escapes column and table names
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000417 *
418 * @access private
Rick Ellis605a07a2008-10-17 04:07:54 +0000419 * @param string
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000420 * @return string
421 */
Rick Ellis605a07a2008-10-17 04:07:54 +0000422 function _escape_identifiers($item)
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000423 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000424 if ($this->_escape_char == '')
Derek Allardd2df9bc2007-04-15 17:41:17 +0000425 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000426 return $item;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000427 }
Rick Ellisa0e86292008-10-26 22:46:55 +0000428
429 foreach ($this->_reserved_identifiers as $id)
430 {
431 if (strpos($item, '.'.$id) !== FALSE)
432 {
433 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
434
435 // remove duplicates if the user already included the escape
436 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
437 }
438 }
439
Rick Ellis605a07a2008-10-17 04:07:54 +0000440 if (strpos($item, '.') !== FALSE)
Derek Allard39b622d2008-01-16 21:10:09 +0000441 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000442 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
Derek Allard61579382008-01-16 22:22:42 +0000443 }
444 else
445 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000446 $str = $this->_escape_char.$item.$this->_escape_char;
Derek Allard39b622d2008-01-16 21:10:09 +0000447 }
Derek Allard39b622d2008-01-16 21:10:09 +0000448
Rick Ellis605a07a2008-10-17 04:07:54 +0000449 // remove duplicates if the user already included the escape
450 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
Derek Allard39b622d2008-01-16 21:10:09 +0000451 }
452
453 // --------------------------------------------------------------------
454
455 /**
Derek Jonesc6ad0232008-01-29 18:44:54 +0000456 * From Tables
457 *
458 * This function implicitly groups FROM tables so there is no confusion
459 * about operator precedence in harmony with SQL standards
460 *
461 * @access public
462 * @param type
463 * @return type
464 */
465 function _from_tables($tables)
466 {
Derek Jones0b59f272008-05-13 04:22:33 +0000467 if ( ! is_array($tables))
Derek Jonesc6ad0232008-01-29 18:44:54 +0000468 {
469 $tables = array($tables);
470 }
471
472 return '('.implode(', ', $tables).')';
473 }
474
475 // --------------------------------------------------------------------
476
477 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000478 * Insert statement
479 *
480 * Generates a platform-specific insert string from the supplied data
481 *
482 * @access public
483 * @param string the table name
484 * @param array the insert keys
485 * @param array the insert values
486 * @return string
487 */
488 function _insert($table, $keys, $values)
489 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000490 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
Derek Allardd2df9bc2007-04-15 17:41:17 +0000491 }
492
493 // --------------------------------------------------------------------
494
495 /**
496 * Update statement
497 *
498 * Generates a platform-specific update string from the supplied data
499 *
500 * @access public
501 * @param string the table name
502 * @param array the update data
503 * @param array the where clause
Derek Allard39b622d2008-01-16 21:10:09 +0000504 * @param array the orderby clause
505 * @param array the limit clause
Derek Allardd2df9bc2007-04-15 17:41:17 +0000506 * @return string
507 */
Derek Allard39b622d2008-01-16 21:10:09 +0000508 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000509 {
510 foreach($values as $key => $val)
511 {
512 $valstr[] = $key." = ".$val;
513 }
Derek Allardda6d2402007-12-19 14:49:29 +0000514
Derek Jones0b59f272008-05-13 04:22:33 +0000515 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
Derek Allard39b622d2008-01-16 21:10:09 +0000516
517 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
Derek Allardd2df9bc2007-04-15 17:41:17 +0000518
Rick Ellis605a07a2008-10-17 04:07:54 +0000519 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
520
Derek Allard32cf7eb2008-02-05 16:03:50 +0000521 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
Rick Ellis605a07a2008-10-17 04:07:54 +0000522
Derek Allard32cf7eb2008-02-05 16:03:50 +0000523 $sql .= $orderby.$limit;
524
525 return $sql;
Derek Allard39b622d2008-01-16 21:10:09 +0000526 }
527
528
529 // --------------------------------------------------------------------
530
531 /**
532 * Truncate statement
533 *
534 * Generates a platform-specific truncate string from the supplied data
535 * If the database does not support the truncate() command
536 * This function maps to "DELETE FROM table"
537 *
538 * @access public
539 * @param string the table name
540 * @return string
541 */
542 function _truncate($table)
543 {
Rick Ellis605a07a2008-10-17 04:07:54 +0000544 return "TRUNCATE ".$table;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000545 }
546
547 // --------------------------------------------------------------------
548
549 /**
550 * Delete statement
551 *
552 * Generates a platform-specific delete string from the supplied data
553 *
554 * @access public
555 * @param string the table name
556 * @param array the where clause
Derek Allard39b622d2008-01-16 21:10:09 +0000557 * @param string the limit clause
Derek Allardd2df9bc2007-04-15 17:41:17 +0000558 * @return string
559 */
Derek Allard39b622d2008-01-16 21:10:09 +0000560 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000561 {
Derek Allard39b622d2008-01-16 21:10:09 +0000562 $conditions = '';
563
Derek Jones0b59f272008-05-13 04:22:33 +0000564 if (count($where) > 0 OR count($like) > 0)
Derek Allard39b622d2008-01-16 21:10:09 +0000565 {
566 $conditions = "\nWHERE ";
567 $conditions .= implode("\n", $this->ar_where);
568
569 if (count($where) > 0 && count($like) > 0)
570 {
571 $conditions .= " AND ";
572 }
573 $conditions .= implode("\n", $like);
574 }
575
Derek Jones0b59f272008-05-13 04:22:33 +0000576 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
Derek Allarde77d77c2007-12-19 15:01:55 +0000577
Derek Allard39b622d2008-01-16 21:10:09 +0000578 return "DELETE FROM ".$table.$conditions.$limit;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000579 }
580
581 // --------------------------------------------------------------------
582
583 /**
584 * Limit string
585 *
586 * Generates a platform-specific LIMIT clause
587 *
588 * @access public
589 * @param string the sql query string
590 * @param integer the number of rows to limit the query to
591 * @param integer the offset value
592 * @return string
593 */
594 function _limit($sql, $limit, $offset)
595 {
596 $sql .= "LIMIT ".$limit;
597
598 if ($offset > 0)
599 {
600 $sql .= " OFFSET ".$offset;
601 }
602
603 return $sql;
604 }
605
606 // --------------------------------------------------------------------
607
608 /**
609 * Close DB Connection
610 *
611 * @access public
612 * @param resource
613 * @return void
614 */
615 function _close($conn_id)
616 {
617 @mysqli_close($conn_id);
618 }
619
620
621}
622
Derek Jones0b59f272008-05-13 04:22:33 +0000623
624/* End of file mysqli_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000625/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */