CodeIgniter installed
[living-lab-site.git] / system / database / drivers / mysqli / mysqli_driver.php
1 <?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  * 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  */
31 class 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         // clause and character used for LIKE escape sequences - not used in MySQL
39         var $_like_escape_str = '';
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 = ' RAND()'; // database specific random keyword
49
50         /**
51          * Whether to use the MySQL "delete hack" which allows the number
52          * of affected rows to be shown. Uses a preg_replace when enabled,
53          * adding a bit more processing to all queries.
54          */
55         var $delete_hack = TRUE;
56
57         // --------------------------------------------------------------------
58
59         /**
60          * Non-persistent database connection
61          *
62          * @access      private called by the base class
63          * @return      resource
64          */
65         function db_connect()
66         {
67                 if ($this->port != '')
68                 {
69                         return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port);
70                 }
71                 else
72                 {
73                         return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
74                 }
75
76         }
77
78         // --------------------------------------------------------------------
79
80         /**
81          * Persistent database connection
82          *
83          * @access      private called by the base class
84          * @return      resource
85          */
86         function db_pconnect()
87         {
88                 return $this->db_connect();
89         }
90
91         // --------------------------------------------------------------------
92
93         /**
94          * Reconnect
95          *
96          * Keep / reestablish the db connection if no queries have been
97          * sent for a length of time exceeding the server's idle timeout
98          *
99          * @access      public
100          * @return      void
101          */
102         function reconnect()
103         {
104                 if (mysqli_ping($this->conn_id) === FALSE)
105                 {
106                         $this->conn_id = FALSE;
107                 }
108         }
109
110         // --------------------------------------------------------------------
111
112         /**
113          * Select the database
114          *
115          * @access      private called by the base class
116          * @return      resource
117          */
118         function db_select()
119         {
120                 return @mysqli_select_db($this->conn_id, $this->database);
121         }
122
123         // --------------------------------------------------------------------
124
125         /**
126          * Set client character set
127          *
128          * @access      private
129          * @param       string
130          * @param       string
131          * @return      resource
132          */
133         function _db_set_charset($charset, $collation)
134         {
135                 return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
136         }
137
138         // --------------------------------------------------------------------
139
140         /**
141          * Version number query string
142          *
143          * @access      public
144          * @return      string
145          */
146         function _version()
147         {
148                 return "SELECT version() AS ver";
149         }
150
151         // --------------------------------------------------------------------
152
153         /**
154          * Execute the query
155          *
156          * @access      private called by the base class
157          * @param       string  an SQL query
158          * @return      resource
159          */
160         function _execute($sql)
161         {
162                 $sql = $this->_prep_query($sql);
163                 $result = @mysqli_query($this->conn_id, $sql);
164                 return $result;
165         }
166
167         // --------------------------------------------------------------------
168
169         /**
170          * Prep the query
171          *
172          * If needed, each database adapter can prep the query string
173          *
174          * @access      private called by execute()
175          * @param       string  an SQL query
176          * @return      string
177          */
178         function _prep_query($sql)
179         {
180                 // "DELETE FROM TABLE" returns 0 affected rows This hack modifies
181                 // the query so that it returns the number of affected rows
182                 if ($this->delete_hack === TRUE)
183                 {
184                         if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
185                         {
186                                 $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql);
187                         }
188                 }
189
190                 return $sql;
191         }
192
193         // --------------------------------------------------------------------
194
195         /**
196          * Begin Transaction
197          *
198          * @access      public
199          * @return      bool
200          */
201         function trans_begin($test_mode = FALSE)
202         {
203                 if ( ! $this->trans_enabled)
204                 {
205                         return TRUE;
206                 }
207
208                 // When transactions are nested we only begin/commit/rollback the outermost ones
209                 if ($this->_trans_depth > 0)
210                 {
211                         return TRUE;
212                 }
213
214                 // Reset the transaction failure flag.
215                 // If the $test_mode flag is set to TRUE transactions will be rolled back
216                 // even if the queries produce a successful result.
217                 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
218
219                 $this->simple_query('SET AUTOCOMMIT=0');
220                 $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
221                 return TRUE;
222         }
223
224         // --------------------------------------------------------------------
225
226         /**
227          * Commit Transaction
228          *
229          * @access      public
230          * @return      bool
231          */
232         function trans_commit()
233         {
234                 if ( ! $this->trans_enabled)
235                 {
236                         return TRUE;
237                 }
238
239                 // When transactions are nested we only begin/commit/rollback the outermost ones
240                 if ($this->_trans_depth > 0)
241                 {
242                         return TRUE;
243                 }
244
245                 $this->simple_query('COMMIT');
246                 $this->simple_query('SET AUTOCOMMIT=1');
247                 return TRUE;
248         }
249
250         // --------------------------------------------------------------------
251
252         /**
253          * Rollback Transaction
254          *
255          * @access      public
256          * @return      bool
257          */
258         function trans_rollback()
259         {
260                 if ( ! $this->trans_enabled)
261                 {
262                         return TRUE;
263                 }
264
265                 // When transactions are nested we only begin/commit/rollback the outermost ones
266                 if ($this->_trans_depth > 0)
267                 {
268                         return TRUE;
269                 }
270
271                 $this->simple_query('ROLLBACK');
272                 $this->simple_query('SET AUTOCOMMIT=1');
273                 return TRUE;
274         }
275
276         // --------------------------------------------------------------------
277
278         /**
279          * Escape String
280          *
281          * @access      public
282          * @param       string
283          * @param       bool    whether or not the string will be used in a LIKE condition
284          * @return      string
285          */
286         function escape_str($str, $like = FALSE)
287         {
288                 if (is_array($str))
289                 {
290                         foreach ($str as $key => $val)
291                         {
292                                 $str[$key] = $this->escape_str($val, $like);
293                         }
294
295                         return $str;
296                 }
297
298                 if (function_exists('mysqli_real_escape_string') AND is_object($this->conn_id))
299                 {
300                         $str = mysqli_real_escape_string($this->conn_id, $str);
301                 }
302                 elseif (function_exists('mysql_escape_string'))
303                 {
304                         $str = mysql_escape_string($str);
305                 }
306                 else
307                 {
308                         $str = addslashes($str);
309                 }
310
311                 // escape LIKE condition wildcards
312                 if ($like === TRUE)
313                 {
314                         $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str);
315                 }
316
317                 return $str;
318         }
319
320         // --------------------------------------------------------------------
321
322         /**
323          * Affected Rows
324          *
325          * @access      public
326          * @return      integer
327          */
328         function affected_rows()
329         {
330                 return @mysqli_affected_rows($this->conn_id);
331         }
332
333         // --------------------------------------------------------------------
334
335         /**
336          * Insert ID
337          *
338          * @access      public
339          * @return      integer
340          */
341         function insert_id()
342         {
343                 return @mysqli_insert_id($this->conn_id);
344         }
345
346         // --------------------------------------------------------------------
347
348         /**
349          * "Count All" query
350          *
351          * Generates a platform-specific query string that counts all records in
352          * the specified database
353          *
354          * @access      public
355          * @param       string
356          * @return      string
357          */
358         function count_all($table = '')
359         {
360                 if ($table == '')
361                 {
362                         return 0;
363                 }
364
365                 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
366
367                 if ($query->num_rows() == 0)
368                 {
369                         return 0;
370                 }
371
372                 $row = $query->row();
373                 return (int) $row->numrows;
374         }
375
376         // --------------------------------------------------------------------
377
378         /**
379          * List table query
380          *
381          * Generates a platform-specific query string so that the table names can be fetched
382          *
383          * @access      private
384          * @param       boolean
385          * @return      string
386          */
387         function _list_tables($prefix_limit = FALSE)
388         {
389                 $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;
390
391                 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
392                 {
393                         $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'";
394                 }
395
396                 return $sql;
397         }
398
399         // --------------------------------------------------------------------
400
401         /**
402          * Show column query
403          *
404          * Generates a platform-specific query string so that the column names can be fetched
405          *
406          * @access      public
407          * @param       string  the table name
408          * @return      string
409          */
410         function _list_columns($table = '')
411         {
412                 return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE);
413         }
414
415         // --------------------------------------------------------------------
416
417         /**
418          * Field data query
419          *
420          * Generates a platform-specific query so that the column data can be retrieved
421          *
422          * @access      public
423          * @param       string  the table name
424          * @return      object
425          */
426         function _field_data($table)
427         {
428                 return "SELECT * FROM ".$table." LIMIT 1";
429         }
430
431         // --------------------------------------------------------------------
432
433         /**
434          * The error message string
435          *
436          * @access      private
437          * @return      string
438          */
439         function _error_message()
440         {
441                 return mysqli_error($this->conn_id);
442         }
443
444         // --------------------------------------------------------------------
445
446         /**
447          * The error message number
448          *
449          * @access      private
450          * @return      integer
451          */
452         function _error_number()
453         {
454                 return mysqli_errno($this->conn_id);
455         }
456
457         // --------------------------------------------------------------------
458
459         /**
460          * Escape the SQL Identifiers
461          *
462          * This function escapes column and table names
463          *
464          * @access      private
465          * @param       string
466          * @return      string
467          */
468         function _escape_identifiers($item)
469         {
470                 if ($this->_escape_char == '')
471                 {
472                         return $item;
473                 }
474
475                 foreach ($this->_reserved_identifiers as $id)
476                 {
477                         if (strpos($item, '.'.$id) !== FALSE)
478                         {
479                                 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
480
481                                 // remove duplicates if the user already included the escape
482                                 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
483                         }
484                 }
485
486                 if (strpos($item, '.') !== FALSE)
487                 {
488                         $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
489                 }
490                 else
491                 {
492                         $str = $this->_escape_char.$item.$this->_escape_char;
493                 }
494
495                 // remove duplicates if the user already included the escape
496                 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
497         }
498
499         // --------------------------------------------------------------------
500
501         /**
502          * From Tables
503          *
504          * This function implicitly groups FROM tables so there is no confusion
505          * about operator precedence in harmony with SQL standards
506          *
507          * @access      public
508          * @param       type
509          * @return      type
510          */
511         function _from_tables($tables)
512         {
513                 if ( ! is_array($tables))
514                 {
515                         $tables = array($tables);
516                 }
517
518                 return '('.implode(', ', $tables).')';
519         }
520
521         // --------------------------------------------------------------------
522
523         /**
524          * Insert statement
525          *
526          * Generates a platform-specific insert string from the supplied data
527          *
528          * @access      public
529          * @param       string  the table name
530          * @param       array   the insert keys
531          * @param       array   the insert values
532          * @return      string
533          */
534         function _insert($table, $keys, $values)
535         {
536                 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
537         }
538
539         // --------------------------------------------------------------------
540
541         /**
542          * Insert_batch statement
543          *
544          * Generates a platform-specific insert string from the supplied data
545          *
546          * @access      public
547          * @param       string  the table name
548          * @param       array   the insert keys
549          * @param       array   the insert values
550          * @return      string
551          */
552         function _insert_batch($table, $keys, $values)
553         {
554                 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values);
555         }
556         
557         // --------------------------------------------------------------------
558
559         /**
560          * Update statement
561          *
562          * Generates a platform-specific update string from the supplied data
563          *
564          * @access      public
565          * @param       string  the table name
566          * @param       array   the update data
567          * @param       array   the where clause
568          * @param       array   the orderby clause
569          * @param       array   the limit clause
570          * @return      string
571          */
572         function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
573         {
574                 foreach ($values as $key => $val)
575                 {
576                         $valstr[] = $key." = ".$val;
577                 }
578
579                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
580
581                 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
582
583                 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
584
585                 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
586
587                 $sql .= $orderby.$limit;
588
589                 return $sql;
590         }
591
592         // --------------------------------------------------------------------
593
594         /**
595          * Update_Batch statement
596          *
597          * Generates a platform-specific batch update string from the supplied data
598          *
599          * @access      public
600          * @param       string  the table name
601          * @param       array   the update data
602          * @param       array   the where clause
603          * @return      string
604          */
605         function _update_batch($table, $values, $index, $where = NULL)
606         {
607                 $ids = array();
608                 $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : '';
609
610                 foreach ($values as $key => $val)
611                 {
612                         $ids[] = $val[$index];
613
614                         foreach (array_keys($val) as $field)
615                         {
616                                 if ($field != $index)
617                                 {
618                                         $final[$field][] =  'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
619                                 }
620                         }
621                 }
622
623                 $sql = "UPDATE ".$table." SET ";
624                 $cases = '';
625
626                 foreach ($final as $k => $v)
627                 {
628                         $cases .= $k.' = CASE '."\n";
629                         foreach ($v as $row)
630                         {
631                                 $cases .= $row."\n";
632                         }
633
634                         $cases .= 'ELSE '.$k.' END, ';
635                 }
636
637                 $sql .= substr($cases, 0, -2);
638
639                 $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
640
641                 return $sql;
642         }
643
644         // --------------------------------------------------------------------
645
646         /**
647          * Truncate statement
648          *
649          * Generates a platform-specific truncate string from the supplied data
650          * If the database does not support the truncate() command
651          * This function maps to "DELETE FROM table"
652          *
653          * @access      public
654          * @param       string  the table name
655          * @return      string
656          */
657         function _truncate($table)
658         {
659                 return "TRUNCATE ".$table;
660         }
661
662         // --------------------------------------------------------------------
663
664         /**
665          * Delete statement
666          *
667          * Generates a platform-specific delete string from the supplied data
668          *
669          * @access      public
670          * @param       string  the table name
671          * @param       array   the where clause
672          * @param       string  the limit clause
673          * @return      string
674          */
675         function _delete($table, $where = array(), $like = array(), $limit = FALSE)
676         {
677                 $conditions = '';
678
679                 if (count($where) > 0 OR count($like) > 0)
680                 {
681                         $conditions = "\nWHERE ";
682                         $conditions .= implode("\n", $this->ar_where);
683
684                         if (count($where) > 0 && count($like) > 0)
685                         {
686                                 $conditions .= " AND ";
687                         }
688                         $conditions .= implode("\n", $like);
689                 }
690
691                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
692
693                 return "DELETE FROM ".$table.$conditions.$limit;
694         }
695
696         // --------------------------------------------------------------------
697
698         /**
699          * Limit string
700          *
701          * Generates a platform-specific LIMIT clause
702          *
703          * @access      public
704          * @param       string  the sql query string
705          * @param       integer the number of rows to limit the query to
706          * @param       integer the offset value
707          * @return      string
708          */
709         function _limit($sql, $limit, $offset)
710         {
711                 $sql .= "LIMIT ".$limit;
712
713                 if ($offset > 0)
714                 {
715                         $sql .= " OFFSET ".$offset;
716                 }
717
718                 return $sql;
719         }
720
721         // --------------------------------------------------------------------
722
723         /**
724          * Close DB Connection
725          *
726          * @access      public
727          * @param       resource
728          * @return      void
729          */
730         function _close($conn_id)
731         {
732                 @mysqli_close($conn_id);
733         }
734
735
736 }
737
738
739 /* End of file mysqli_driver.php */
740 /* Location: ./system/database/drivers/mysqli/mysqli_driver.php */