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