blob: 2b05c3f159d9696fb8558cfe372f833ed27167bc [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 * 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 */
31class CI_DB_mysql_driver extends CI_DB {
32
33 var $dbdriver = 'mysql';
34
35 // The character used for escaping
36 var $_escape_char = '`';
Derek Jonese4ed5832009-02-20 21:44:59 +000037
38 // clause and character used for LIKE escape sequences - not used in MySQL
39 var $_like_escape_str = '';
40 var $_like_escape_chr = '';
41
Derek Allard2067d1a2008-11-13 22:59:24 +000042 /**
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 * Select the database
95 *
96 * @access private called by the base class
97 * @return resource
98 */
99 function db_select()
100 {
101 return @mysql_select_db($this->database, $this->conn_id);
102 }
103
104 // --------------------------------------------------------------------
105
106 /**
107 * Set client character set
108 *
109 * @access public
110 * @param string
111 * @param string
112 * @return resource
113 */
114 function db_set_charset($charset, $collation)
115 {
116 return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id);
117 }
118
119 // --------------------------------------------------------------------
120
121 /**
122 * Version number query string
123 *
124 * @access public
125 * @return string
126 */
127 function _version()
128 {
129 return "SELECT version() AS ver";
130 }
131
132 // --------------------------------------------------------------------
133
134 /**
135 * Execute the query
136 *
137 * @access private called by the base class
138 * @param string an SQL query
139 * @return resource
140 */
141 function _execute($sql)
142 {
143 $sql = $this->_prep_query($sql);
144 return @mysql_query($sql, $this->conn_id);
145 }
146
147 // --------------------------------------------------------------------
148
149 /**
150 * Prep the query
151 *
152 * If needed, each database adapter can prep the query string
153 *
154 * @access private called by execute()
155 * @param string an SQL query
156 * @return string
157 */
158 function _prep_query($sql)
159 {
160 // "DELETE FROM TABLE" returns 0 affected rows This hack modifies
161 // the query so that it returns the number of affected rows
162 if ($this->delete_hack === TRUE)
163 {
164 if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
165 {
166 $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql);
167 }
168 }
169
170 return $sql;
171 }
172
173 // --------------------------------------------------------------------
174
175 /**
176 * Begin Transaction
177 *
178 * @access public
179 * @return bool
180 */
181 function trans_begin($test_mode = FALSE)
182 {
183 if ( ! $this->trans_enabled)
184 {
185 return TRUE;
186 }
187
188 // When transactions are nested we only begin/commit/rollback the outermost ones
189 if ($this->_trans_depth > 0)
190 {
191 return TRUE;
192 }
193
194 // Reset the transaction failure flag.
195 // If the $test_mode flag is set to TRUE transactions will be rolled back
196 // even if the queries produce a successful result.
197 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
198
199 $this->simple_query('SET AUTOCOMMIT=0');
200 $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
201 return TRUE;
202 }
203
204 // --------------------------------------------------------------------
205
206 /**
207 * Commit Transaction
208 *
209 * @access public
210 * @return bool
211 */
212 function trans_commit()
213 {
214 if ( ! $this->trans_enabled)
215 {
216 return TRUE;
217 }
218
219 // When transactions are nested we only begin/commit/rollback the outermost ones
220 if ($this->_trans_depth > 0)
221 {
222 return TRUE;
223 }
224
225 $this->simple_query('COMMIT');
226 $this->simple_query('SET AUTOCOMMIT=1');
227 return TRUE;
228 }
229
230 // --------------------------------------------------------------------
231
232 /**
233 * Rollback Transaction
234 *
235 * @access public
236 * @return bool
237 */
238 function trans_rollback()
239 {
240 if ( ! $this->trans_enabled)
241 {
242 return TRUE;
243 }
244
245 // When transactions are nested we only begin/commit/rollback the outermost ones
246 if ($this->_trans_depth > 0)
247 {
248 return TRUE;
249 }
250
251 $this->simple_query('ROLLBACK');
252 $this->simple_query('SET AUTOCOMMIT=1');
253 return TRUE;
254 }
255
256 // --------------------------------------------------------------------
257
258 /**
259 * Escape String
260 *
261 * @access public
262 * @param string
Derek Jonese4ed5832009-02-20 21:44:59 +0000263 * @param bool whether or not the string will be used in a LIKE condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000264 * @return string
265 */
Derek Jonese4ed5832009-02-20 21:44:59 +0000266 function escape_str($str, $like = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000267 {
268 if (is_array($str))
269 {
270 foreach($str as $key => $val)
271 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000272 $str[$key] = $this->escape_str($val, $like);
Derek Allard2067d1a2008-11-13 22:59:24 +0000273 }
274
275 return $str;
276 }
277
278 if (function_exists('mysql_real_escape_string') AND is_resource($this->conn_id))
279 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000280 $str = mysql_real_escape_string($str, $this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000281 }
282 elseif (function_exists('mysql_escape_string'))
283 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000284 $str = mysql_escape_string($str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000285 }
286 else
287 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000288 $str = addslashes($str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000289 }
Derek Jonese4ed5832009-02-20 21:44:59 +0000290
291 // escape LIKE condition wildcards
292 if ($like === TRUE)
293 {
294 $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str);
295 }
296
297 return $str;
Derek Allard2067d1a2008-11-13 22:59:24 +0000298 }
299
300 // --------------------------------------------------------------------
301
302 /**
303 * Affected Rows
304 *
305 * @access public
306 * @return integer
307 */
308 function affected_rows()
309 {
310 return @mysql_affected_rows($this->conn_id);
311 }
312
313 // --------------------------------------------------------------------
314
315 /**
316 * Insert ID
317 *
318 * @access public
319 * @return integer
320 */
321 function insert_id()
322 {
323 return @mysql_insert_id($this->conn_id);
324 }
325
326 // --------------------------------------------------------------------
327
328 /**
329 * "Count All" query
330 *
331 * Generates a platform-specific query string that counts all records in
332 * the specified database
333 *
334 * @access public
335 * @param string
336 * @return string
337 */
338 function count_all($table = '')
339 {
340 if ($table == '')
Derek Allarde37ab382009-02-03 16:13:57 +0000341 {
342 return 0;
343 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000344
Derek Allarde37ab382009-02-03 16:13:57 +0000345 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
346
Derek Allard2067d1a2008-11-13 22:59:24 +0000347 if ($query->num_rows() == 0)
Derek Allarde37ab382009-02-03 16:13:57 +0000348 {
349 return 0;
350 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000351
352 $row = $query->row();
Derek Allarde37ab382009-02-03 16:13:57 +0000353 return (int) $row->numrows;
Derek Allard2067d1a2008-11-13 22:59:24 +0000354 }
355
356 // --------------------------------------------------------------------
357
358 /**
359 * List table query
360 *
361 * Generates a platform-specific query string so that the table names can be fetched
362 *
363 * @access private
364 * @param boolean
365 * @return string
366 */
367 function _list_tables($prefix_limit = FALSE)
368 {
369 $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;
370
371 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
372 {
Derek Jones3c11b6f2009-02-20 22:36:27 +0000373 $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'";
Derek Allard2067d1a2008-11-13 22:59:24 +0000374 }
375
376 return $sql;
377 }
378
379 // --------------------------------------------------------------------
380
381 /**
382 * Show column query
383 *
384 * Generates a platform-specific query string so that the column names can be fetched
385 *
386 * @access public
387 * @param string the table name
388 * @return string
389 */
390 function _list_columns($table = '')
391 {
392 return "SHOW COLUMNS FROM ".$table;
393 }
394
395 // --------------------------------------------------------------------
396
397 /**
398 * Field data query
399 *
400 * Generates a platform-specific query so that the column data can be retrieved
401 *
402 * @access public
403 * @param string the table name
404 * @return object
405 */
406 function _field_data($table)
407 {
408 return "SELECT * FROM ".$table." LIMIT 1";
409 }
410
411 // --------------------------------------------------------------------
412
413 /**
414 * The error message string
415 *
416 * @access private
417 * @return string
418 */
419 function _error_message()
420 {
421 return mysql_error($this->conn_id);
422 }
423
424 // --------------------------------------------------------------------
425
426 /**
427 * The error message number
428 *
429 * @access private
430 * @return integer
431 */
432 function _error_number()
433 {
434 return mysql_errno($this->conn_id);
435 }
436
437 // --------------------------------------------------------------------
438
439 /**
440 * Escape the SQL Identifiers
441 *
442 * This function escapes column and table names
443 *
444 * @access private
445 * @param string
446 * @return string
447 */
448 function _escape_identifiers($item)
449 {
450 if ($this->_escape_char == '')
451 {
452 return $item;
453 }
454
455 foreach ($this->_reserved_identifiers as $id)
456 {
457 if (strpos($item, '.'.$id) !== FALSE)
458 {
459 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
460
461 // remove duplicates if the user already included the escape
462 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
463 }
464 }
465
466 if (strpos($item, '.') !== FALSE)
467 {
468 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
469 }
470 else
471 {
472 $str = $this->_escape_char.$item.$this->_escape_char;
473 }
474
475 // remove duplicates if the user already included the escape
476 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
477 }
478
479 // --------------------------------------------------------------------
480
481 /**
482 * From Tables
483 *
484 * This function implicitly groups FROM tables so there is no confusion
485 * about operator precedence in harmony with SQL standards
486 *
487 * @access public
488 * @param type
489 * @return type
490 */
491 function _from_tables($tables)
492 {
493 if ( ! is_array($tables))
494 {
495 $tables = array($tables);
496 }
497
498 return '('.implode(', ', $tables).')';
499 }
500
501 // --------------------------------------------------------------------
502
503 /**
504 * Insert statement
505 *
506 * Generates a platform-specific insert string from the supplied data
507 *
508 * @access public
509 * @param string the table name
510 * @param array the insert keys
511 * @param array the insert values
512 * @return string
513 */
514 function _insert($table, $keys, $values)
515 {
516 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
517 }
518
519 // --------------------------------------------------------------------
520
521 /**
522 * Update statement
523 *
524 * Generates a platform-specific update string from the supplied data
525 *
526 * @access public
527 * @param string the table name
528 * @param array the update data
529 * @param array the where clause
530 * @param array the orderby clause
531 * @param array the limit clause
532 * @return string
533 */
534 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
535 {
536 foreach($values as $key => $val)
537 {
538 $valstr[] = $key." = ".$val;
539 }
540
541 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
542
543 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
544
545 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
546
547 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
548
549 $sql .= $orderby.$limit;
550
551 return $sql;
552 }
553
554 // --------------------------------------------------------------------
555
556 /**
557 * Truncate statement
558 *
559 * Generates a platform-specific truncate string from the supplied data
560 * If the database does not support the truncate() command
561 * This function maps to "DELETE FROM table"
562 *
563 * @access public
564 * @param string the table name
565 * @return string
566 */
567 function _truncate($table)
568 {
569 return "TRUNCATE ".$table;
570 }
571
572 // --------------------------------------------------------------------
573
574 /**
575 * Delete statement
576 *
577 * Generates a platform-specific delete string from the supplied data
578 *
579 * @access public
580 * @param string the table name
581 * @param array the where clause
582 * @param string the limit clause
583 * @return string
584 */
585 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
586 {
587 $conditions = '';
588
589 if (count($where) > 0 OR count($like) > 0)
590 {
591 $conditions = "\nWHERE ";
592 $conditions .= implode("\n", $this->ar_where);
593
594 if (count($where) > 0 && count($like) > 0)
595 {
596 $conditions .= " AND ";
597 }
598 $conditions .= implode("\n", $like);
599 }
600
601 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
602
603 return "DELETE FROM ".$table.$conditions.$limit;
604 }
605
606 // --------------------------------------------------------------------
607
608 /**
609 * Limit string
610 *
611 * Generates a platform-specific LIMIT clause
612 *
613 * @access public
614 * @param string the sql query string
615 * @param integer the number of rows to limit the query to
616 * @param integer the offset value
617 * @return string
618 */
619 function _limit($sql, $limit, $offset)
620 {
621 if ($offset == 0)
622 {
623 $offset = '';
624 }
625 else
626 {
627 $offset .= ", ";
628 }
629
630 return $sql."LIMIT ".$offset.$limit;
631 }
632
633 // --------------------------------------------------------------------
634
635 /**
636 * Close DB Connection
637 *
638 * @access public
639 * @param resource
640 * @return void
641 */
642 function _close($conn_id)
643 {
644 @mysql_close($conn_id);
645 }
646
647}
648
649
650/* End of file mysql_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000651/* Location: ./system/database/drivers/mysql/mysql_driver.php */