blob: ce458f292dc7b8eab7121452d920dc1f2cc052a7 [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 == '')
319 return '0';
320
321 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
322
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
338 * @param boolean
339 * @return string
340 */
341 function _list_tables($prefix_limit = FALSE)
342 {
343 $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;
344
345 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
346 {
347 $sql .= " LIKE '".$this->dbprefix."%'";
348 }
349
350 return $sql;
351 }
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 {
366 return "SHOW COLUMNS FROM ".$table;
367 }
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 {
382 return "SELECT * FROM ".$table." LIMIT 1";
383 }
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 }
410
411 // --------------------------------------------------------------------
412
413 /**
414 * Escape the SQL Identifiers
415 *
416 * This function escapes column and table names
417 *
418 * @access private
419 * @param string
420 * @return string
421 */
422 function _escape_identifiers($item)
423 {
424 if ($this->_escape_char == '')
425 {
426 return $item;
427 }
428
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
440 if (strpos($item, '.') !== FALSE)
441 {
442 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
443 }
444 else
445 {
446 $str = $this->_escape_char.$item.$this->_escape_char;
447 }
448
449 // remove duplicates if the user already included the escape
450 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
451 }
452
453 // --------------------------------------------------------------------
454
455 /**
456 * 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 {
467 if ( ! is_array($tables))
468 {
469 $tables = array($tables);
470 }
471
472 return '('.implode(', ', $tables).')';
473 }
474
475 // --------------------------------------------------------------------
476
477 /**
478 * 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 {
490 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
491 }
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
504 * @param array the orderby clause
505 * @param array the limit clause
506 * @return string
507 */
508 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
509 {
510 foreach($values as $key => $val)
511 {
512 $valstr[] = $key." = ".$val;
513 }
514
515 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
516
517 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
518
519 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
520
521 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
522
523 $sql .= $orderby.$limit;
524
525 return $sql;
526 }
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 {
544 return "TRUNCATE ".$table;
545 }
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
557 * @param string the limit clause
558 * @return string
559 */
560 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
561 {
562 $conditions = '';
563
564 if (count($where) > 0 OR count($like) > 0)
565 {
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
576 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
577
578 return "DELETE FROM ".$table.$conditions.$limit;
579 }
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
623
624/* End of file mysqli_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000625/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */