blob: 9ef18e0255fe77cfd8e17c2b536ace813b7e14ee [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 * 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
28 * @author ExpressionEngine Dev Team
29 * @link http://codeigniter.com/user_guide/database/
30 */
31class CI_DB_mysqli_driver extends CI_DB {
32
33 var $dbdriver = 'mysqli';
34
35 // The character used for escaping
36 var $_escape_char = '`';
37
38 /**
39 * 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 */
43 var $_count_string = "SELECT COUNT(*) AS ";
44 var $_random_keyword = ' RAND()'; // database specific random keyword
45
46 /**
47 * 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 {
63 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
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 {
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 /**
103 * Set client character set
104 *
105 * @access private
106 * @param string
107 * @param string
108 * @return resource
109 */
110 function _db_set_charset($charset, $collation)
111 {
112 return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
113 }
114
115 // --------------------------------------------------------------------
116
117 /**
118 * 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 {
180 if ( ! $this->trans_enabled)
181 {
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 {
211 if ( ! $this->trans_enabled)
212 {
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 {
237 if ( ! $this->trans_enabled)
238 {
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)
263 {
264 if (function_exists('mysqli_real_escape_string') AND is_object($this->conn_id))
265 {
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 }
276 }
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 == '')
Derek Allarde37ab382009-02-03 16:13:57 +0000319 {
320 return 0;
321 }
322
323 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
324
Derek Allard2067d1a2008-11-13 22:59:24 +0000325 if ($query->num_rows() == 0)
Derek Allarde37ab382009-02-03 16:13:57 +0000326 {
327 return 0;
328 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000329
330 $row = $query->row();
Derek Allarde37ab382009-02-03 16:13:57 +0000331 return (int) $row->numrows;
Derek Allard2067d1a2008-11-13 22:59:24 +0000332 }
333
334 // --------------------------------------------------------------------
335
336 /**
337 * List table query
338 *
339 * Generates a platform-specific query string so that the table names can be fetched
340 *
341 * @access private
342 * @param boolean
343 * @return string
344 */
345 function _list_tables($prefix_limit = FALSE)
346 {
347 $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;
348
349 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
350 {
351 $sql .= " LIKE '".$this->dbprefix."%'";
352 }
353
354 return $sql;
355 }
356
357 // --------------------------------------------------------------------
358
359 /**
360 * Show column query
361 *
362 * Generates a platform-specific query string so that the column names can be fetched
363 *
364 * @access public
365 * @param string the table name
366 * @return string
367 */
368 function _list_columns($table = '')
369 {
370 return "SHOW COLUMNS FROM ".$table;
371 }
372
373 // --------------------------------------------------------------------
374
375 /**
376 * Field data query
377 *
378 * Generates a platform-specific query so that the column data can be retrieved
379 *
380 * @access public
381 * @param string the table name
382 * @return object
383 */
384 function _field_data($table)
385 {
386 return "SELECT * FROM ".$table." LIMIT 1";
387 }
388
389 // --------------------------------------------------------------------
390
391 /**
392 * The error message string
393 *
394 * @access private
395 * @return string
396 */
397 function _error_message()
398 {
399 return mysqli_error($this->conn_id);
400 }
401
402 // --------------------------------------------------------------------
403
404 /**
405 * The error message number
406 *
407 * @access private
408 * @return integer
409 */
410 function _error_number()
411 {
412 return mysqli_errno($this->conn_id);
413 }
414
415 // --------------------------------------------------------------------
416
417 /**
418 * Escape the SQL Identifiers
419 *
420 * This function escapes column and table names
421 *
422 * @access private
423 * @param string
424 * @return string
425 */
426 function _escape_identifiers($item)
427 {
428 if ($this->_escape_char == '')
429 {
430 return $item;
431 }
432
433 foreach ($this->_reserved_identifiers as $id)
434 {
435 if (strpos($item, '.'.$id) !== FALSE)
436 {
437 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
438
439 // remove duplicates if the user already included the escape
440 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
441 }
442 }
443
444 if (strpos($item, '.') !== FALSE)
445 {
446 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
447 }
448 else
449 {
450 $str = $this->_escape_char.$item.$this->_escape_char;
451 }
452
453 // remove duplicates if the user already included the escape
454 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
455 }
456
457 // --------------------------------------------------------------------
458
459 /**
460 * From Tables
461 *
462 * This function implicitly groups FROM tables so there is no confusion
463 * about operator precedence in harmony with SQL standards
464 *
465 * @access public
466 * @param type
467 * @return type
468 */
469 function _from_tables($tables)
470 {
471 if ( ! is_array($tables))
472 {
473 $tables = array($tables);
474 }
475
476 return '('.implode(', ', $tables).')';
477 }
478
479 // --------------------------------------------------------------------
480
481 /**
482 * Insert statement
483 *
484 * Generates a platform-specific insert string from the supplied data
485 *
486 * @access public
487 * @param string the table name
488 * @param array the insert keys
489 * @param array the insert values
490 * @return string
491 */
492 function _insert($table, $keys, $values)
493 {
494 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
495 }
496
497 // --------------------------------------------------------------------
498
499 /**
500 * Update statement
501 *
502 * Generates a platform-specific update string from the supplied data
503 *
504 * @access public
505 * @param string the table name
506 * @param array the update data
507 * @param array the where clause
508 * @param array the orderby clause
509 * @param array the limit clause
510 * @return string
511 */
512 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
513 {
514 foreach($values as $key => $val)
515 {
516 $valstr[] = $key." = ".$val;
517 }
518
519 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
520
521 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
522
523 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
524
525 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
526
527 $sql .= $orderby.$limit;
528
529 return $sql;
530 }
531
532
533 // --------------------------------------------------------------------
534
535 /**
536 * Truncate statement
537 *
538 * Generates a platform-specific truncate string from the supplied data
539 * If the database does not support the truncate() command
540 * This function maps to "DELETE FROM table"
541 *
542 * @access public
543 * @param string the table name
544 * @return string
545 */
546 function _truncate($table)
547 {
548 return "TRUNCATE ".$table;
549 }
550
551 // --------------------------------------------------------------------
552
553 /**
554 * Delete statement
555 *
556 * Generates a platform-specific delete string from the supplied data
557 *
558 * @access public
559 * @param string the table name
560 * @param array the where clause
561 * @param string the limit clause
562 * @return string
563 */
564 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
565 {
566 $conditions = '';
567
568 if (count($where) > 0 OR count($like) > 0)
569 {
570 $conditions = "\nWHERE ";
571 $conditions .= implode("\n", $this->ar_where);
572
573 if (count($where) > 0 && count($like) > 0)
574 {
575 $conditions .= " AND ";
576 }
577 $conditions .= implode("\n", $like);
578 }
579
580 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
581
582 return "DELETE FROM ".$table.$conditions.$limit;
583 }
584
585 // --------------------------------------------------------------------
586
587 /**
588 * Limit string
589 *
590 * Generates a platform-specific LIMIT clause
591 *
592 * @access public
593 * @param string the sql query string
594 * @param integer the number of rows to limit the query to
595 * @param integer the offset value
596 * @return string
597 */
598 function _limit($sql, $limit, $offset)
599 {
600 $sql .= "LIMIT ".$limit;
601
602 if ($offset > 0)
603 {
604 $sql .= " OFFSET ".$offset;
605 }
606
607 return $sql;
608 }
609
610 // --------------------------------------------------------------------
611
612 /**
613 * Close DB Connection
614 *
615 * @access public
616 * @param resource
617 * @return void
618 */
619 function _close($conn_id)
620 {
621 @mysqli_close($conn_id);
622 }
623
624
625}
626
627
628/* End of file mysqli_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000629/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */