blob: 1cebb189c946ecd896d8c33973ea82988da2276e [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
Derek Jonesf4a4bd82011-10-20 12:18:42 -05003 * CodeIgniter
Derek Allard2067d1a2008-11-13 22:59:24 +00004 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev24276a32012-01-08 02:44:38 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev24276a32012-01-08 02:44:38 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Andrey Andreev80500af2013-01-01 08:16:53 +020021 * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020027defined('BASEPATH') OR exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +000028
Derek Allard2067d1a2008-11-13 22:59:24 +000029/**
Andrey Andreevd947eba2012-04-09 14:58:28 +030030 * Database Forge Class
Derek Allard2067d1a2008-11-13 22:59:24 +000031 *
32 * @category Database
Derek Jonesf4a4bd82011-10-20 12:18:42 -050033 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000034 * @link http://codeigniter.com/user_guide/database/
35 */
Timothy Warren833d5042012-03-19 16:12:03 -040036abstract class CI_DB_forge {
Derek Allard2067d1a2008-11-13 22:59:24 +000037
Andrey Andreevae85eb42012-11-02 01:42:31 +020038 /**
Andrey Andreeva287a342012-11-05 23:19:59 +020039 * Database object
40 *
41 * @var object
42 */
Andrey Andreeveaa60c72012-11-06 01:11:22 +020043 protected $db;
Andrey Andreeva287a342012-11-05 23:19:59 +020044
45 /**
Andrey Andreevae85eb42012-11-02 01:42:31 +020046 * Fields data
47 *
48 * @var array
49 */
Andrey Andreev24276a32012-01-08 02:44:38 +020050 public $fields = array();
Andrey Andreevae85eb42012-11-02 01:42:31 +020051
52 /**
53 * Keys data
54 *
55 * @var array
56 */
Andrey Andreev24276a32012-01-08 02:44:38 +020057 public $keys = array();
Andrey Andreevae85eb42012-11-02 01:42:31 +020058
59 /**
60 * Primary Keys data
61 *
62 * @var array
63 */
Andrey Andreev24276a32012-01-08 02:44:38 +020064 public $primary_keys = array();
Andrey Andreevae85eb42012-11-02 01:42:31 +020065
66 /**
67 * Database character set
68 *
69 * @var string
70 */
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030071 public $db_char_set = '';
Derek Allard2067d1a2008-11-13 22:59:24 +000072
Andrey Andreevae85eb42012-11-02 01:42:31 +020073 // --------------------------------------------------------------------
74
75 /**
76 * CREATE DATABASE statement
77 *
78 * @var string
79 */
Andrey Andreevd947eba2012-04-09 14:58:28 +030080 protected $_create_database = 'CREATE DATABASE %s';
Andrey Andreevae85eb42012-11-02 01:42:31 +020081
82 /**
83 * DROP DATABASE statement
84 *
85 * @var string
86 */
Andrey Andreevd947eba2012-04-09 14:58:28 +030087 protected $_drop_database = 'DROP DATABASE %s';
Andrey Andreevae85eb42012-11-02 01:42:31 +020088
89 /**
Andrey Andreeva287a342012-11-05 23:19:59 +020090 * CREATE TABLE statement
Andrey Andreevae85eb42012-11-02 01:42:31 +020091 *
92 * @var string
93 */
Andrey Andreeva287a342012-11-05 23:19:59 +020094 protected $_create_table = "%s %s (%s\n)";
95
96 /**
97 * CREATE TABLE IF statement
98 *
99 * @var string
100 */
101 protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
102
103 /**
104 * CREATE TABLE keys flag
105 *
106 * Whether table keys are created from within the
107 * CREATE TABLE statement.
108 *
109 * @var bool
110 */
111 protected $_create_table_keys = FALSE;
112
113 /**
114 * DROP TABLE IF EXISTS statement
115 *
116 * @var string
117 */
118 protected $_drop_table_if = 'DROP TABLE IF EXISTS';
Andrey Andreevae85eb42012-11-02 01:42:31 +0200119
120 /**
121 * RENAME TABLE statement
122 *
123 * @var string
124 */
Andrey Andreeva287a342012-11-05 23:19:59 +0200125 protected $_rename_table = 'ALTER TABLE %s RENAME TO %s;';
126
127 /**
128 * UNSIGNED support
129 *
130 * @var bool|array
131 */
132 protected $_unsigned = TRUE;
133
134 /**
135 * NULL value representatin in CREATE/ALTER TABLE statements
136 *
137 * @var string
138 */
139 protected $_null = '';
140
141 /**
142 * DEFAULT value representation in CREATE/ALTER TABLE statements
143 *
144 * @var string
145 */
146 protected $_default = ' DEFAULT ';
Andrey Andreevd947eba2012-04-09 14:58:28 +0300147
Andrey Andreevae85eb42012-11-02 01:42:31 +0200148 // --------------------------------------------------------------------
149
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300150 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200151 * Class constructor
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300152 *
Andrey Andreeveaa60c72012-11-06 01:11:22 +0200153 * @param object &$db Database object
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300154 * @return void
155 */
Andrey Andreeveaa60c72012-11-06 01:11:22 +0200156 public function __construct(&$db)
Derek Allard2067d1a2008-11-13 22:59:24 +0000157 {
Andrey Andreeveaa60c72012-11-06 01:11:22 +0200158 $this->db =& $db;
Andrey Andreev24276a32012-01-08 02:44:38 +0200159 log_message('debug', 'Database Forge Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000160 }
161
162 // --------------------------------------------------------------------
163
164 /**
165 * Create database
166 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200167 * @param string $db_name
Derek Allard2067d1a2008-11-13 22:59:24 +0000168 * @return bool
169 */
Andrey Andreev24276a32012-01-08 02:44:38 +0200170 public function create_database($db_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000171 {
Andrey Andreevd947eba2012-04-09 14:58:28 +0300172 if ($this->_create_database === FALSE)
173 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200174 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300175 }
176 elseif ( ! $this->db->query(sprintf($this->_create_database, $db_name, $this->db->char_set, $this->db->dbcollat)))
177 {
178 return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
179 }
180
Andrey Andreev5d281762012-06-11 22:05:40 +0300181 if ( ! empty($this->db->data_cache['db_names']))
182 {
183 $this->db->data_cache['db_names'][] = $db_name;
184 }
185
Andrey Andreevd947eba2012-04-09 14:58:28 +0300186 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000187 }
188
189 // --------------------------------------------------------------------
190
191 /**
192 * Drop database
193 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200194 * @param string $db_name
Derek Allard2067d1a2008-11-13 22:59:24 +0000195 * @return bool
196 */
Andrey Andreev24276a32012-01-08 02:44:38 +0200197 public function drop_database($db_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000198 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100199 if ($db_name === '')
Andrey Andreevd947eba2012-04-09 14:58:28 +0300200 {
201 show_error('A table name is required for that operation.');
202 return FALSE;
203 }
204 elseif ($this->_drop_database === FALSE)
205 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200206 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300207 }
208 elseif ( ! $this->db->query(sprintf($this->_drop_database, $db_name)))
209 {
210 return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
211 }
212
Andrey Andreev5d281762012-06-11 22:05:40 +0300213 if ( ! empty($this->db->data_cache['db_names']))
214 {
215 $key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
216 if ($key !== FALSE)
217 {
218 unset($this->db->data_cache['db_names'][$key]);
219 }
220 }
221
Andrey Andreevd947eba2012-04-09 14:58:28 +0300222 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000223 }
224
225 // --------------------------------------------------------------------
226
227 /**
228 * Add Key
229 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200230 * @param string $key
231 * @param bool $primary
Andrey Andreevd8dba5d2012-12-17 15:42:01 +0200232 * @return CI_DB_forge
Derek Allard2067d1a2008-11-13 22:59:24 +0000233 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000234 public function add_key($key = '', $primary = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000235 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200236 if (empty($key))
237 {
238 show_error('Key information is required for that operation.');
239 }
240
Andrey Andreevd743cdb2012-11-06 00:00:01 +0200241 if ($primary === TRUE && is_array($key))
Derek Allard2067d1a2008-11-13 22:59:24 +0000242 {
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500243 foreach ($key as $one)
Derek Allard2067d1a2008-11-13 22:59:24 +0000244 {
245 $this->add_key($one, $primary);
246 }
Barry Mienydd671972010-10-04 16:33:58 +0200247
Andrey Andreeva287a342012-11-05 23:19:59 +0200248 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000249 }
Barry Mienydd671972010-10-04 16:33:58 +0200250
Derek Allard2067d1a2008-11-13 22:59:24 +0000251 if ($primary === TRUE)
252 {
253 $this->primary_keys[] = $key;
254 }
255 else
256 {
257 $this->keys[] = $key;
258 }
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000259
260 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000261 }
262
263 // --------------------------------------------------------------------
264
265 /**
266 * Add Field
267 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200268 * @param array $field
Andrew Podner4296a652012-12-17 07:51:15 -0500269 * @return CI_DB_forge
Derek Allard2067d1a2008-11-13 22:59:24 +0000270 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000271 public function add_field($field = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000272 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200273 if (empty($field))
Derek Allard2067d1a2008-11-13 22:59:24 +0000274 {
275 show_error('Field information is required.');
276 }
Barry Mienydd671972010-10-04 16:33:58 +0200277
Derek Allard2067d1a2008-11-13 22:59:24 +0000278 if (is_string($field))
279 {
Andrey Andreev24276a32012-01-08 02:44:38 +0200280 if ($field === 'id')
Derek Allard2067d1a2008-11-13 22:59:24 +0000281 {
282 $this->add_field(array(
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000283 'id' => array(
284 'type' => 'INT',
285 'constraint' => 9,
286 'auto_increment' => TRUE
287 )
288 ));
Derek Allard2067d1a2008-11-13 22:59:24 +0000289 $this->add_key('id', TRUE);
290 }
291 else
292 {
293 if (strpos($field, ' ') === FALSE)
294 {
295 show_error('Field information is required for that operation.');
296 }
Barry Mienydd671972010-10-04 16:33:58 +0200297
Derek Allard2067d1a2008-11-13 22:59:24 +0000298 $this->fields[] = $field;
299 }
300 }
Barry Mienydd671972010-10-04 16:33:58 +0200301
Derek Allard2067d1a2008-11-13 22:59:24 +0000302 if (is_array($field))
303 {
304 $this->fields = array_merge($this->fields, $field);
305 }
Andrey Andreev24276a32012-01-08 02:44:38 +0200306
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000307 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000308 }
309
310 // --------------------------------------------------------------------
311
312 /**
313 * Create Table
314 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200315 * @param string $table Table name
316 * @param bool $if_not_exists Whether to add IF NOT EXISTS condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000317 * @return bool
318 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000319 public function create_table($table = '', $if_not_exists = FALSE)
Barry Mienydd671972010-10-04 16:33:58 +0200320 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100321 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000322 {
323 show_error('A table name is required for that operation.');
324 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200325 else
326 {
327 $table = $this->db->dbprefix.$table;
328 }
Barry Mienydd671972010-10-04 16:33:58 +0200329
Andrey Andreev24276a32012-01-08 02:44:38 +0200330 if (count($this->fields) === 0)
Barry Mienydd671972010-10-04 16:33:58 +0200331 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000332 show_error('Field information is required.');
333 }
334
Andrey Andreeva287a342012-11-05 23:19:59 +0200335 $sql = $this->_create_table($table, $if_not_exists);
Andrey Andreev5d281762012-06-11 22:05:40 +0300336
337 if (is_bool($sql))
338 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200339 $this->_reset();
340 if ($sql === FALSE)
341 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200342 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200343 }
Andrey Andreev5d281762012-06-11 22:05:40 +0300344 }
345
Andrey Andreeva287a342012-11-05 23:19:59 +0200346 if (($result = $this->db->query($sql)) !== FALSE)
Andrey Andreev5d281762012-06-11 22:05:40 +0300347 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200348 empty($this->db->data_cache['table_names']) OR $this->db->data_cache['table_names'][] = $table;
349
350 // Most databases don't support creating indexes from within the CREATE TABLE statement
351 if ( ! empty($this->keys))
352 {
353 for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
354 {
355 $this->db->query($sqls[$i]);
356 }
357 }
Andrey Andreev5d281762012-06-11 22:05:40 +0300358 }
359
Andrey Andreeva287a342012-11-05 23:19:59 +0200360 $this->_reset();
Andrey Andreev5d281762012-06-11 22:05:40 +0300361 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000362 }
363
364 // --------------------------------------------------------------------
365
366 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200367 * Create Table
368 *
369 * @param string $table Table name
370 * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition
371 * @return mixed
372 */
373 protected function _create_table($table, $if_not_exists)
374 {
375 if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
376 {
377 if ($this->db->table_exists($table))
378 {
379 return TRUE;
380 }
381 else
382 {
383 $if_not_exists = FALSE;
384 }
385 }
386
387 $sql = ($if_not_exists)
388 ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table))
389 : 'CREATE TABLE';
390
391 $columns = $this->_process_fields(TRUE);
392 for ($i = 0, $c = count($columns); $i < $c; $i++)
393 {
394 $columns[$i] = ($columns[$i]['_literal'] !== FALSE)
395 ? "\n\t".$columns[$i]['_literal']
396 : "\n\t".$this->_process_column($columns[$i]);
397 }
398
399 $columns = implode(',', $columns)
400 .$this->_process_primary_keys($table);
401
402 // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
403 if ($this->_create_table_keys === TRUE)
404 {
Andrey Andreev35451022012-11-25 17:20:04 +0200405 $columns .= $this->_process_indexes($table);
Andrey Andreeva287a342012-11-05 23:19:59 +0200406 }
407
408 // _create_table will usually have the following format: "%s %s (%s\n)"
409 $sql = sprintf($this->_create_table.';',
410 $sql,
411 $this->db->escape_identifiers($table),
412 $columns
413 );
414
415 return $sql;
416 }
417
418 // --------------------------------------------------------------------
419
420 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000421 * Drop Table
422 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200423 * @param string $table_name Table name
424 * @param bool $if_exists Whether to add an IF EXISTS condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000425 * @return bool
426 */
Andrey Andreeva287a342012-11-05 23:19:59 +0200427 public function drop_table($table_name, $if_exists = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100429 if ($table_name === '')
Andrey Andreevd947eba2012-04-09 14:58:28 +0300430 {
431 return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
432 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200433
434 $query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists);
435 if ($query === FALSE)
Andrey Andreevd947eba2012-04-09 14:58:28 +0300436 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200437 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300438 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200439 elseif ($query === TRUE)
440 {
441 return TRUE;
442 }
Andrey Andreevd947eba2012-04-09 14:58:28 +0300443
Andrey Andreeva287a342012-11-05 23:19:59 +0200444 $query = $this->db->query($query);
Andrey Andreev5d281762012-06-11 22:05:40 +0300445
446 // Update table list cache
Andrey Andreeva287a342012-11-05 23:19:59 +0200447 if ($query && ! empty($this->db->data_cache['table_names']))
Andrey Andreev5d281762012-06-11 22:05:40 +0300448 {
449 $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
450 if ($key !== FALSE)
451 {
452 unset($this->db->data_cache['table_names'][$key]);
453 }
454 }
455
Andrey Andreeva287a342012-11-05 23:19:59 +0200456 return $query;
457 }
458
459 // --------------------------------------------------------------------
460
461 /**
462 * Drop Table
463 *
464 * Generates a platform-specific DROP TABLE string
465 *
466 * @param string $table Table name
467 * @param bool $if_exists Whether to add an IF EXISTS condition
468 * @return string
469 */
470 protected function _drop_table($table, $if_exists)
471 {
472 $sql = 'DROP TABLE';
473
474 if ($if_exists)
475 {
476 if ($this->_drop_table_if === FALSE)
477 {
478 if ( ! $this->db->table_exists($table))
479 {
480 return TRUE;
481 }
482 }
483 else
484 {
485 $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
486 }
487 }
488
489 return $sql.' '.$this->db->escape_identifiers($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000490 }
491
492 // --------------------------------------------------------------------
493
494 /**
495 * Rename Table
496 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200497 * @param string $table_name Old table name
498 * @param string $new_table_name New table name
Derek Allard2067d1a2008-11-13 22:59:24 +0000499 * @return bool
500 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000501 public function rename_table($table_name, $new_table_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000502 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100503 if ($table_name === '' OR $new_table_name === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000504 {
505 show_error('A table name is required for that operation.');
Andrey Andreevd947eba2012-04-09 14:58:28 +0300506 return FALSE;
507 }
508 elseif ($this->_rename_table === FALSE)
509 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200510 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000511 }
Barry Mienydd671972010-10-04 16:33:58 +0200512
Andrey Andreev5d281762012-06-11 22:05:40 +0300513 $result = $this->db->query(sprintf($this->_rename_table,
Andrey Andreevd947eba2012-04-09 14:58:28 +0300514 $this->db->escape_identifiers($this->db->dbprefix.$table_name),
515 $this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
516 );
Andrey Andreev5d281762012-06-11 22:05:40 +0300517
518 if ($result && ! empty($this->db->data_cache['table_names']))
519 {
520 $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
521 if ($key !== FALSE)
522 {
523 $this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
524 }
525 }
526
527 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000528 }
529
530 // --------------------------------------------------------------------
531
532 /**
533 * Column Add
534 *
Andrey Andreevb67277b2012-11-12 12:51:14 +0200535 * @todo Remove deprecated $_after option in 3.1+
Andrey Andreeva287a342012-11-05 23:19:59 +0200536 * @param string $table Table name
537 * @param array $field Column definition
Andrey Andreevb67277b2012-11-12 12:51:14 +0200538 * @param string $_after Column for AFTER clause (deprecated)
Derek Allard2067d1a2008-11-13 22:59:24 +0000539 * @return bool
540 */
Andrey Andreevb67277b2012-11-12 12:51:14 +0200541 public function add_column($table = '', $field = array(), $_after = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000542 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100543 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000544 {
545 show_error('A table name is required for that operation.');
546 }
547
Andrey Andreeva287a342012-11-05 23:19:59 +0200548 // Work-around for literal column definitions
549 if ( ! is_array($field))
550 {
551 $field = array($field);
552 }
553
Andrey Andreev24276a32012-01-08 02:44:38 +0200554 foreach (array_keys($field) as $k)
Barry Mienydd671972010-10-04 16:33:58 +0200555 {
Andrey Andreevb67277b2012-11-12 12:51:14 +0200556 // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
557 if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
558 {
559 $field[$k]['after'] = $_after;
560 }
561
Barry Mienydd671972010-10-04 16:33:58 +0200562 $this->add_field(array($k => $field[$k]));
Andrey Andreeva287a342012-11-05 23:19:59 +0200563 }
Robin Sowell8a54ef22009-03-04 14:49:53 +0000564
Andrey Andreeva287a342012-11-05 23:19:59 +0200565 $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
566 $this->_reset();
567 if ($sqls === FALSE)
568 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200569 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200570 }
Barry Mienydd671972010-10-04 16:33:58 +0200571
Andrey Andreeva287a342012-11-05 23:19:59 +0200572 for ($i = 0, $c = count($sqls); $i < $c; $i++)
573 {
Andrey Andreev137a7422012-11-05 23:46:44 +0200574 if ($this->db->query($sqls[$i]) === FALSE)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000575 {
576 return FALSE;
577 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000578 }
Barry Mienydd671972010-10-04 16:33:58 +0200579
Robin Sowell8a54ef22009-03-04 14:49:53 +0000580 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000581 }
582
583 // --------------------------------------------------------------------
584
585 /**
586 * Column Drop
587 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200588 * @param string $table Table name
589 * @param string $column_name Column name
Derek Allard2067d1a2008-11-13 22:59:24 +0000590 * @return bool
591 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000592 public function drop_column($table = '', $column_name = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000593 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100594 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000595 {
596 show_error('A table name is required for that operation.');
597 }
598
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100599 if ($column_name === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000600 {
601 show_error('A column name is required for that operation.');
602 }
603
Andrey Andreeva287a342012-11-05 23:19:59 +0200604 $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
605 if ($sql === FALSE)
606 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200607 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200608 }
609
610 return $this->db->query($sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000611 }
612
613 // --------------------------------------------------------------------
614
615 /**
616 * Column Modify
617 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200618 * @param string $table Table name
619 * @param string $field Column definition
Derek Allard2067d1a2008-11-13 22:59:24 +0000620 * @return bool
621 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000622 public function modify_column($table = '', $field = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000623 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100624 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000625 {
626 show_error('A table name is required for that operation.');
627 }
628
Andrey Andreeva287a342012-11-05 23:19:59 +0200629 // Work-around for literal column definitions
630 if ( ! is_array($field))
631 {
632 $field = array($field);
633 }
634
Andrey Andreev24276a32012-01-08 02:44:38 +0200635 foreach (array_keys($field) as $k)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000636 {
637 $this->add_field(array($k => $field[$k]));
Andrey Andreeva287a342012-11-05 23:19:59 +0200638 }
Barry Mienydd671972010-10-04 16:33:58 +0200639
Andrey Andreeva287a342012-11-05 23:19:59 +0200640 if (count($this->fields) === 0)
641 {
642 show_error('Field information is required.');
643 }
Barry Mienydd671972010-10-04 16:33:58 +0200644
Andrey Andreev7ade8b72012-11-22 13:12:22 +0200645 $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
Andrey Andreeva287a342012-11-05 23:19:59 +0200646 $this->_reset();
647 if ($sqls === FALSE)
648 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200649 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200650 }
651
652 for ($i = 0, $c = count($sqls); $i < $c; $i++)
653 {
Andrey Andreev137a7422012-11-05 23:46:44 +0200654 if ($this->db->query($sqls[$i]) === FALSE)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000655 {
656 return FALSE;
657 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000658 }
Barry Mienydd671972010-10-04 16:33:58 +0200659
Robin Sowell8a54ef22009-03-04 14:49:53 +0000660 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000661 }
662
663 // --------------------------------------------------------------------
664
665 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200666 * ALTER TABLE
667 *
668 * @param string $alter_type ALTER type
669 * @param string $table Table name
670 * @param mixed $field Column definition
671 * @return string|string[]
672 */
673 protected function _alter_table($alter_type, $table, $field)
674 {
675 $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
676
677 // DROP has everything it needs now.
678 if ($alter_type === 'DROP')
679 {
680 return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
681 }
682
Andrey Andreev13f6eab2013-03-15 10:56:55 +0200683 $sql .= ($alter_type === 'ADD')
684 ? 'ADD '
685 : $alter_type.' COLUMN ';
686
Andrey Andreeva287a342012-11-05 23:19:59 +0200687 $sqls = array();
Andrey Andreev13f6eab2013-03-15 10:56:55 +0200688 for ($i = 0, $c = count($field); $i < $c; $i++)
Andrey Andreeva287a342012-11-05 23:19:59 +0200689 {
690 $sqls[] = $sql
691 .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
692 }
693
694 return $sqls;
695 }
696
697 // --------------------------------------------------------------------
698
699 /**
700 * Process fields
701 *
702 * @param bool $create_table
703 * @return array
704 */
705 protected function _process_fields($create_table = FALSE)
706 {
707 $fields = array();
708
709 foreach ($this->fields as $key => $attributes)
710 {
711 if (is_int($key) && ! is_array($attributes))
712 {
713 $fields[] = array('_literal' => $attributes);
714 continue;
715 }
716
717 $attributes = array_change_key_case($attributes, CASE_UPPER);
718
719 if ($create_table === TRUE && empty($attributes['TYPE']))
720 {
721 continue;
722 }
723
724 if (isset($attributes['TYPE']))
725 {
726 $this->_attr_type($attributes);
727 $this->_attr_unsigned($attributes, $field);
728 }
729
730 $field = array(
731 'name' => $key,
732 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
733 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
734 'length' => '',
735 'unsigned' => '',
736 'null' => '',
737 'unique' => '',
738 'default' => '',
739 'auto_increment' => '',
740 '_literal' => FALSE
741 );
742
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200743 if ($create_table === FALSE)
744 {
745 if (isset($attributes['AFTER']))
746 {
Andrey Andreev96185a32013-10-28 16:04:02 +0200747 $field['after'] = $attributes['AFTER'];
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200748 }
749 elseif (isset($attributes['FIRST']))
750 {
751 $field['first'] = (bool) $attributes['FIRST'];
752 }
753 }
754
Andrey Andreeva287a342012-11-05 23:19:59 +0200755 $this->_attr_default($attributes, $field);
756
757 if (isset($attributes['NULL']))
758 {
759 if ($attributes['NULL'] === TRUE)
760 {
761 $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
762 }
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200763 else
Andrey Andreeva287a342012-11-05 23:19:59 +0200764 {
765 $field['null'] = ' NOT NULL';
766 }
767 }
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200768 elseif ($create_table === TRUE)
769 {
770 $field['null'] = ' NOT NULL';
771 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200772
773 $this->_attr_auto_increment($attributes, $field);
774 $this->_attr_unique($attributes, $field);
775
776 if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
777 {
778 switch (strtoupper($attributes['TYPE']))
779 {
780 case 'ENUM':
781 case 'SET':
782 $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
783 default:
784 $field['length'] = is_array($attributes['CONSTRAINT'])
Andrey Andreev356d4f42012-11-19 20:13:11 +0200785 ? "('".implode("','", $attributes['CONSTRAINT'])."')"
Andrey Andreeva287a342012-11-05 23:19:59 +0200786 : '('.$attributes['CONSTRAINT'].')';
787 break;
788 }
789 }
790
791 $fields[] = $field;
792 }
793
794 return $fields;
795 }
796
797 // --------------------------------------------------------------------
798
799 /**
800 * Process column
801 *
802 * @param array $field
803 * @return string
804 */
805 protected function _process_column($field)
806 {
807 return $this->db->escape_identifiers($field['name'])
808 .' '.$field['type'].$field['length']
809 .$field['unsigned']
810 .$field['default']
811 .$field['null']
812 .$field['auto_increment']
813 .$field['unique'];
814 }
815
816 // --------------------------------------------------------------------
817
818 /**
819 * Field attribute TYPE
820 *
821 * Performs a data type mapping between different databases.
822 *
823 * @param array &$attributes
824 * @return void
825 */
826 protected function _attr_type(&$attributes)
827 {
828 // Usually overriden by drivers
829 }
830
831 // --------------------------------------------------------------------
832
833 /**
834 * Field attribute UNSIGNED
835 *
836 * Depending on the _unsigned property value:
837 *
838 * - TRUE will always set $field['unsigned'] to 'UNSIGNED'
839 * - FALSE will always set $field['unsigned'] to ''
840 * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
841 * if $attributes['TYPE'] is found in the array
842 * - array(TYPE => UTYPE) will change $field['type'],
843 * from TYPE to UTYPE in case of a match
844 *
845 * @param array &$attributes
846 * @param array &$field
847 * @return void
848 */
849 protected function _attr_unsigned(&$attributes, &$field)
850 {
851 if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
852 {
853 return;
854 }
855
856 // Reset the attribute in order to avoid issues if we do type conversion
857 $attributes['UNSIGNED'] = FALSE;
858
859 if (is_array($this->_unsigned))
860 {
861 foreach (array_keys($this->_unsigned) as $key)
862 {
863 if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
864 {
865 $field['unsigned'] = ' UNSIGNED';
866 return;
867 }
868 elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
869 {
870 $field['type'] = $key;
871 return;
872 }
873 }
874
875 return;
876 }
877
878 $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
879 }
880
881 // --------------------------------------------------------------------
882
883 /**
884 * Field attribute DEFAULT
885 *
886 * @param array &$attributes
887 * @param array &$field
888 * @return void
889 */
890 protected function _attr_default(&$attributes, &$field)
891 {
892 if ($this->_default === FALSE)
893 {
894 return;
895 }
896
897 if (array_key_exists('DEFAULT', $attributes))
898 {
899 if ($attributes['DEFAULT'] === NULL)
900 {
901 $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
902
903 // Override the NULL attribute if that's our default
904 $attributes['NULL'] = NULL;
905 $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
906 }
907 else
908 {
909 $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
910 }
911 }
912 }
913
914 // --------------------------------------------------------------------
915
916 /**
917 * Field attribute UNIQUE
918 *
919 * @param array &$attributes
920 * @param array &$field
921 * @return void
922 */
923 protected function _attr_unique(&$attributes, &$field)
924 {
925 if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
926 {
927 $field['unique'] = ' UNIQUE';
928 }
929 }
930
931 // --------------------------------------------------------------------
932
933 /**
934 * Field attribute AUTO_INCREMENT
935 *
936 * @param array &$attributes
937 * @param array &$field
938 * @return void
939 */
940 protected function _attr_auto_increment(&$attributes, &$field)
941 {
942 if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
943 {
944 $field['auto_increment'] = ' AUTO_INCREMENT';
945 }
946 }
947
948 // --------------------------------------------------------------------
949
950 /**
951 * Process primary keys
952 *
953 * @param string $table Table name
954 * @return string
955 */
956 protected function _process_primary_keys($table)
957 {
958 $sql = '';
959
960 for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
961 {
962 if ( ! isset($this->fields[$this->primary_keys[$i]]))
963 {
964 unset($this->primary_keys[$i]);
965 }
966 }
967
968 if (count($this->primary_keys) > 0)
969 {
970 $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
971 .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
972 }
973
974 return $sql;
975 }
976
977 // --------------------------------------------------------------------
978
979 /**
980 * Process indexes
981 *
982 * @param string $table
983 * @return string
984 */
Andrey Andreev35451022012-11-25 17:20:04 +0200985 protected function _process_indexes($table)
Andrey Andreeva287a342012-11-05 23:19:59 +0200986 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200987 $sqls = array();
988
989 for ($i = 0, $c = count($this->keys); $i < $c; $i++)
990 {
Andrey Andreev35451022012-11-25 17:20:04 +0200991 if (is_array($this->keys[$i]))
992 {
993 for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
994 {
995 if ( ! isset($this->fields[$this->keys[$i][$i2]]))
996 {
997 unset($this->keys[$i][$i2]);
998 continue;
999 }
1000 }
1001 }
1002 elseif ( ! isset($this->fields[$this->keys[$i]]))
Andrey Andreeva287a342012-11-05 23:19:59 +02001003 {
1004 unset($this->keys[$i]);
1005 continue;
1006 }
1007
1008 is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
1009
mjnaderid3a6ca22013-12-19 01:35:57 +03301010 $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
1011 .' ON '.$this->db->escape_identifiers($table)
Andrey Andreeva287a342012-11-05 23:19:59 +02001012 .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
1013 }
1014
1015 return $sqls;
1016 }
1017
1018 // --------------------------------------------------------------------
1019
1020 /**
Derek Allard2067d1a2008-11-13 22:59:24 +00001021 * Reset
1022 *
1023 * Resets table creation vars
1024 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001025 * @return void
1026 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +00001027 protected function _reset()
Derek Allard2067d1a2008-11-13 22:59:24 +00001028 {
Andrey Andreev24276a32012-01-08 02:44:38 +02001029 $this->fields = $this->keys = $this->primary_keys = array();
Derek Allard2067d1a2008-11-13 22:59:24 +00001030 }
1031
1032}
1033
1034/* End of file DB_forge.php */
Timothy Warren215890b2012-03-20 09:38:16 -04001035/* Location: ./system/database/DB_forge.php */