blob: 111546ecc92e21d20e36736d1099aac4a2a55ac6 [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
darwinel871754a2014-02-11 17:34:57 +010021 * @copyright Copyright (c) 2008 - 2014, 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
Andrey Andreev27f798b2014-01-20 18:19:13 +0200317 * @param array $attributes Associative array of table attributes
Derek Allard2067d1a2008-11-13 22:59:24 +0000318 * @return bool
319 */
Andrey Andreev27f798b2014-01-20 18:19:13 +0200320 public function create_table($table = '', $if_not_exists = FALSE, array $attributes = array())
Barry Mienydd671972010-10-04 16:33:58 +0200321 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100322 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000323 {
324 show_error('A table name is required for that operation.');
325 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200326 else
327 {
328 $table = $this->db->dbprefix.$table;
329 }
Barry Mienydd671972010-10-04 16:33:58 +0200330
Andrey Andreev24276a32012-01-08 02:44:38 +0200331 if (count($this->fields) === 0)
Barry Mienydd671972010-10-04 16:33:58 +0200332 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000333 show_error('Field information is required.');
334 }
335
Andrey Andreev27f798b2014-01-20 18:19:13 +0200336 $sql = $this->_create_table($table, $if_not_exists, $attributes);
Andrey Andreev5d281762012-06-11 22:05:40 +0300337
338 if (is_bool($sql))
339 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200340 $this->_reset();
341 if ($sql === FALSE)
342 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200343 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200344 }
Andrey Andreev5d281762012-06-11 22:05:40 +0300345 }
346
Andrey Andreeva287a342012-11-05 23:19:59 +0200347 if (($result = $this->db->query($sql)) !== FALSE)
Andrey Andreev5d281762012-06-11 22:05:40 +0300348 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200349 empty($this->db->data_cache['table_names']) OR $this->db->data_cache['table_names'][] = $table;
350
351 // Most databases don't support creating indexes from within the CREATE TABLE statement
352 if ( ! empty($this->keys))
353 {
354 for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
355 {
356 $this->db->query($sqls[$i]);
357 }
358 }
Andrey Andreev5d281762012-06-11 22:05:40 +0300359 }
360
Andrey Andreeva287a342012-11-05 23:19:59 +0200361 $this->_reset();
Andrey Andreev5d281762012-06-11 22:05:40 +0300362 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000363 }
364
365 // --------------------------------------------------------------------
366
367 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200368 * Create Table
369 *
370 * @param string $table Table name
371 * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition
Andrey Andreev27f798b2014-01-20 18:19:13 +0200372 * @param array $attributes Associative array of table attributes
Andrey Andreeva287a342012-11-05 23:19:59 +0200373 * @return mixed
374 */
Andrey Andreev27f798b2014-01-20 18:19:13 +0200375 protected function _create_table($table, $if_not_exists, $attributes)
Andrey Andreeva287a342012-11-05 23:19:59 +0200376 {
377 if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
378 {
379 if ($this->db->table_exists($table))
380 {
381 return TRUE;
382 }
383 else
384 {
385 $if_not_exists = FALSE;
386 }
387 }
388
389 $sql = ($if_not_exists)
390 ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table))
391 : 'CREATE TABLE';
392
393 $columns = $this->_process_fields(TRUE);
394 for ($i = 0, $c = count($columns); $i < $c; $i++)
395 {
396 $columns[$i] = ($columns[$i]['_literal'] !== FALSE)
397 ? "\n\t".$columns[$i]['_literal']
398 : "\n\t".$this->_process_column($columns[$i]);
399 }
400
401 $columns = implode(',', $columns)
402 .$this->_process_primary_keys($table);
403
404 // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
405 if ($this->_create_table_keys === TRUE)
406 {
Andrey Andreev35451022012-11-25 17:20:04 +0200407 $columns .= $this->_process_indexes($table);
Andrey Andreeva287a342012-11-05 23:19:59 +0200408 }
409
410 // _create_table will usually have the following format: "%s %s (%s\n)"
Andrey Andreevaaca5cb2014-03-31 17:20:55 +0300411 $sql = sprintf($this->_create_table.'%s',
Andrey Andreeva287a342012-11-05 23:19:59 +0200412 $sql,
413 $this->db->escape_identifiers($table),
Andrey Andreev27f798b2014-01-20 18:19:13 +0200414 $columns,
415 $this->_create_table_attr($attributes)
Andrey Andreeva287a342012-11-05 23:19:59 +0200416 );
417
418 return $sql;
419 }
420
421 // --------------------------------------------------------------------
422
423 /**
Andrey Andreev27f798b2014-01-20 18:19:13 +0200424 * CREATE TABLE attributes
425 *
426 * @param array $attributes Associative array of table attributes
427 * @return string
428 */
429 protected function _create_table_attr($attributes)
430 {
431 $sql = '';
432
433 foreach (array_keys($attributes) as $key)
434 {
435 if (is_string($key))
436 {
437 $sql .= ' '.strtoupper($key).' '.$attributes[$key];
438 }
439 }
440
441 return $sql;
442 }
443
444 // --------------------------------------------------------------------
445
446 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000447 * Drop Table
448 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200449 * @param string $table_name Table name
450 * @param bool $if_exists Whether to add an IF EXISTS condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000451 * @return bool
452 */
Andrey Andreeva287a342012-11-05 23:19:59 +0200453 public function drop_table($table_name, $if_exists = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000454 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100455 if ($table_name === '')
Andrey Andreevd947eba2012-04-09 14:58:28 +0300456 {
457 return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
458 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200459
460 $query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists);
461 if ($query === FALSE)
Andrey Andreevd947eba2012-04-09 14:58:28 +0300462 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200463 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300464 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200465 elseif ($query === TRUE)
466 {
467 return TRUE;
468 }
Andrey Andreevd947eba2012-04-09 14:58:28 +0300469
Andrey Andreeva287a342012-11-05 23:19:59 +0200470 $query = $this->db->query($query);
Andrey Andreev5d281762012-06-11 22:05:40 +0300471
472 // Update table list cache
Andrey Andreeva287a342012-11-05 23:19:59 +0200473 if ($query && ! empty($this->db->data_cache['table_names']))
Andrey Andreev5d281762012-06-11 22:05:40 +0300474 {
475 $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
476 if ($key !== FALSE)
477 {
478 unset($this->db->data_cache['table_names'][$key]);
479 }
480 }
481
Andrey Andreeva287a342012-11-05 23:19:59 +0200482 return $query;
483 }
484
485 // --------------------------------------------------------------------
486
487 /**
488 * Drop Table
489 *
490 * Generates a platform-specific DROP TABLE string
491 *
492 * @param string $table Table name
493 * @param bool $if_exists Whether to add an IF EXISTS condition
494 * @return string
495 */
496 protected function _drop_table($table, $if_exists)
497 {
498 $sql = 'DROP TABLE';
499
500 if ($if_exists)
501 {
502 if ($this->_drop_table_if === FALSE)
503 {
504 if ( ! $this->db->table_exists($table))
505 {
506 return TRUE;
507 }
508 }
509 else
510 {
511 $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
512 }
513 }
514
515 return $sql.' '.$this->db->escape_identifiers($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000516 }
517
518 // --------------------------------------------------------------------
519
520 /**
521 * Rename Table
522 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200523 * @param string $table_name Old table name
524 * @param string $new_table_name New table name
Derek Allard2067d1a2008-11-13 22:59:24 +0000525 * @return bool
526 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000527 public function rename_table($table_name, $new_table_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000528 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100529 if ($table_name === '' OR $new_table_name === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000530 {
531 show_error('A table name is required for that operation.');
Andrey Andreevd947eba2012-04-09 14:58:28 +0300532 return FALSE;
533 }
534 elseif ($this->_rename_table === FALSE)
535 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200536 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000537 }
Barry Mienydd671972010-10-04 16:33:58 +0200538
Andrey Andreev5d281762012-06-11 22:05:40 +0300539 $result = $this->db->query(sprintf($this->_rename_table,
Andrey Andreevd947eba2012-04-09 14:58:28 +0300540 $this->db->escape_identifiers($this->db->dbprefix.$table_name),
541 $this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
542 );
Andrey Andreev5d281762012-06-11 22:05:40 +0300543
544 if ($result && ! empty($this->db->data_cache['table_names']))
545 {
546 $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
547 if ($key !== FALSE)
548 {
549 $this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
550 }
551 }
552
553 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000554 }
555
556 // --------------------------------------------------------------------
557
558 /**
559 * Column Add
560 *
Andrey Andreevb67277b2012-11-12 12:51:14 +0200561 * @todo Remove deprecated $_after option in 3.1+
Andrey Andreeva287a342012-11-05 23:19:59 +0200562 * @param string $table Table name
563 * @param array $field Column definition
Andrey Andreevb67277b2012-11-12 12:51:14 +0200564 * @param string $_after Column for AFTER clause (deprecated)
Derek Allard2067d1a2008-11-13 22:59:24 +0000565 * @return bool
566 */
Andrey Andreevb67277b2012-11-12 12:51:14 +0200567 public function add_column($table = '', $field = array(), $_after = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000568 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100569 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000570 {
571 show_error('A table name is required for that operation.');
572 }
573
Andrey Andreeva287a342012-11-05 23:19:59 +0200574 // Work-around for literal column definitions
575 if ( ! is_array($field))
576 {
577 $field = array($field);
578 }
579
Andrey Andreev24276a32012-01-08 02:44:38 +0200580 foreach (array_keys($field) as $k)
Barry Mienydd671972010-10-04 16:33:58 +0200581 {
Andrey Andreevb67277b2012-11-12 12:51:14 +0200582 // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
583 if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
584 {
585 $field[$k]['after'] = $_after;
586 }
587
Barry Mienydd671972010-10-04 16:33:58 +0200588 $this->add_field(array($k => $field[$k]));
Andrey Andreeva287a342012-11-05 23:19:59 +0200589 }
Robin Sowell8a54ef22009-03-04 14:49:53 +0000590
Andrey Andreeva287a342012-11-05 23:19:59 +0200591 $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
592 $this->_reset();
593 if ($sqls === FALSE)
594 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200595 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200596 }
Barry Mienydd671972010-10-04 16:33:58 +0200597
Andrey Andreeva287a342012-11-05 23:19:59 +0200598 for ($i = 0, $c = count($sqls); $i < $c; $i++)
599 {
Andrey Andreev137a7422012-11-05 23:46:44 +0200600 if ($this->db->query($sqls[$i]) === FALSE)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000601 {
602 return FALSE;
603 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000604 }
Barry Mienydd671972010-10-04 16:33:58 +0200605
Robin Sowell8a54ef22009-03-04 14:49:53 +0000606 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000607 }
608
609 // --------------------------------------------------------------------
610
611 /**
612 * Column Drop
613 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200614 * @param string $table Table name
615 * @param string $column_name Column name
Derek Allard2067d1a2008-11-13 22:59:24 +0000616 * @return bool
617 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000618 public function drop_column($table = '', $column_name = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000619 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100620 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000621 {
622 show_error('A table name is required for that operation.');
623 }
624
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100625 if ($column_name === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000626 {
627 show_error('A column name is required for that operation.');
628 }
629
Andrey Andreeva287a342012-11-05 23:19:59 +0200630 $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
631 if ($sql === FALSE)
632 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200633 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200634 }
635
636 return $this->db->query($sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000637 }
638
639 // --------------------------------------------------------------------
640
641 /**
642 * Column Modify
643 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200644 * @param string $table Table name
645 * @param string $field Column definition
Derek Allard2067d1a2008-11-13 22:59:24 +0000646 * @return bool
647 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000648 public function modify_column($table = '', $field = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000649 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100650 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000651 {
652 show_error('A table name is required for that operation.');
653 }
654
Andrey Andreeva287a342012-11-05 23:19:59 +0200655 // Work-around for literal column definitions
656 if ( ! is_array($field))
657 {
658 $field = array($field);
659 }
660
Andrey Andreev24276a32012-01-08 02:44:38 +0200661 foreach (array_keys($field) as $k)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000662 {
663 $this->add_field(array($k => $field[$k]));
Andrey Andreeva287a342012-11-05 23:19:59 +0200664 }
Barry Mienydd671972010-10-04 16:33:58 +0200665
Andrey Andreeva287a342012-11-05 23:19:59 +0200666 if (count($this->fields) === 0)
667 {
668 show_error('Field information is required.');
669 }
Barry Mienydd671972010-10-04 16:33:58 +0200670
Andrey Andreev7ade8b72012-11-22 13:12:22 +0200671 $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
Andrey Andreeva287a342012-11-05 23:19:59 +0200672 $this->_reset();
673 if ($sqls === FALSE)
674 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200675 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200676 }
677
678 for ($i = 0, $c = count($sqls); $i < $c; $i++)
679 {
Andrey Andreev137a7422012-11-05 23:46:44 +0200680 if ($this->db->query($sqls[$i]) === FALSE)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000681 {
682 return FALSE;
683 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000684 }
Barry Mienydd671972010-10-04 16:33:58 +0200685
Robin Sowell8a54ef22009-03-04 14:49:53 +0000686 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000687 }
688
689 // --------------------------------------------------------------------
690
691 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200692 * ALTER TABLE
693 *
694 * @param string $alter_type ALTER type
695 * @param string $table Table name
696 * @param mixed $field Column definition
697 * @return string|string[]
698 */
699 protected function _alter_table($alter_type, $table, $field)
700 {
701 $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
702
703 // DROP has everything it needs now.
704 if ($alter_type === 'DROP')
705 {
706 return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
707 }
708
Andrey Andreev13f6eab2013-03-15 10:56:55 +0200709 $sql .= ($alter_type === 'ADD')
710 ? 'ADD '
711 : $alter_type.' COLUMN ';
712
Andrey Andreeva287a342012-11-05 23:19:59 +0200713 $sqls = array();
Andrey Andreev13f6eab2013-03-15 10:56:55 +0200714 for ($i = 0, $c = count($field); $i < $c; $i++)
Andrey Andreeva287a342012-11-05 23:19:59 +0200715 {
716 $sqls[] = $sql
717 .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
718 }
719
720 return $sqls;
721 }
722
723 // --------------------------------------------------------------------
724
725 /**
726 * Process fields
727 *
728 * @param bool $create_table
729 * @return array
730 */
731 protected function _process_fields($create_table = FALSE)
732 {
733 $fields = array();
734
735 foreach ($this->fields as $key => $attributes)
736 {
737 if (is_int($key) && ! is_array($attributes))
738 {
739 $fields[] = array('_literal' => $attributes);
740 continue;
741 }
742
743 $attributes = array_change_key_case($attributes, CASE_UPPER);
744
745 if ($create_table === TRUE && empty($attributes['TYPE']))
746 {
747 continue;
748 }
749
Andrey Andreev13943042014-03-17 11:50:45 +0200750 isset($attributes['TYPE']) && $this->_attr_type($attributes);
Andrey Andreeva287a342012-11-05 23:19:59 +0200751
752 $field = array(
Andrey Andreev13943042014-03-17 11:50:45 +0200753 'name' => $key,
754 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
755 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
756 'length' => '',
757 'unsigned' => '',
758 'null' => '',
759 'unique' => '',
760 'default' => '',
761 'auto_increment' => '',
762 '_literal' => FALSE
Andrey Andreeva287a342012-11-05 23:19:59 +0200763 );
764
Andrey Andreev13943042014-03-17 11:50:45 +0200765 isset($attributes['TYPE']) && $this->_attr_unsigned($attributes, $field);
766
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200767 if ($create_table === FALSE)
768 {
769 if (isset($attributes['AFTER']))
770 {
Andrey Andreev96185a32013-10-28 16:04:02 +0200771 $field['after'] = $attributes['AFTER'];
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200772 }
773 elseif (isset($attributes['FIRST']))
774 {
775 $field['first'] = (bool) $attributes['FIRST'];
776 }
777 }
778
Andrey Andreeva287a342012-11-05 23:19:59 +0200779 $this->_attr_default($attributes, $field);
780
781 if (isset($attributes['NULL']))
782 {
783 if ($attributes['NULL'] === TRUE)
784 {
785 $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
786 }
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200787 else
Andrey Andreeva287a342012-11-05 23:19:59 +0200788 {
789 $field['null'] = ' NOT NULL';
790 }
791 }
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200792 elseif ($create_table === TRUE)
793 {
794 $field['null'] = ' NOT NULL';
795 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200796
797 $this->_attr_auto_increment($attributes, $field);
798 $this->_attr_unique($attributes, $field);
799
800 if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
801 {
802 switch (strtoupper($attributes['TYPE']))
803 {
804 case 'ENUM':
805 case 'SET':
806 $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
Andrey Andreevc5a0af22014-03-10 10:29:43 +0200807 $field['length'] = is_array($attributes['CONSTRAINT'])
808 ? "('".implode("','", $attributes['CONSTRAINT'])."')"
809 : '('.$attributes['CONSTRAINT'].')';
Andrey Andreevfde170c2014-03-10 19:55:11 +0200810 break;
Andrey Andreeva287a342012-11-05 23:19:59 +0200811 default:
812 $field['length'] = is_array($attributes['CONSTRAINT'])
Andrey Andreevc5a0af22014-03-10 10:29:43 +0200813 ? '('.implode(',', $attributes['CONSTRAINT']).')'
814 : '('.$attributes['CONSTRAINT'].')';
Andrey Andreeva287a342012-11-05 23:19:59 +0200815 break;
816 }
817 }
818
819 $fields[] = $field;
820 }
821
822 return $fields;
823 }
824
825 // --------------------------------------------------------------------
826
827 /**
828 * Process column
829 *
830 * @param array $field
831 * @return string
832 */
833 protected function _process_column($field)
834 {
835 return $this->db->escape_identifiers($field['name'])
836 .' '.$field['type'].$field['length']
837 .$field['unsigned']
838 .$field['default']
839 .$field['null']
840 .$field['auto_increment']
841 .$field['unique'];
842 }
843
844 // --------------------------------------------------------------------
845
846 /**
847 * Field attribute TYPE
848 *
849 * Performs a data type mapping between different databases.
850 *
851 * @param array &$attributes
852 * @return void
853 */
854 protected function _attr_type(&$attributes)
855 {
856 // Usually overriden by drivers
857 }
858
859 // --------------------------------------------------------------------
860
861 /**
862 * Field attribute UNSIGNED
863 *
864 * Depending on the _unsigned property value:
865 *
866 * - TRUE will always set $field['unsigned'] to 'UNSIGNED'
867 * - FALSE will always set $field['unsigned'] to ''
868 * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
869 * if $attributes['TYPE'] is found in the array
870 * - array(TYPE => UTYPE) will change $field['type'],
871 * from TYPE to UTYPE in case of a match
872 *
873 * @param array &$attributes
874 * @param array &$field
875 * @return void
876 */
877 protected function _attr_unsigned(&$attributes, &$field)
878 {
879 if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
880 {
881 return;
882 }
883
884 // Reset the attribute in order to avoid issues if we do type conversion
885 $attributes['UNSIGNED'] = FALSE;
886
887 if (is_array($this->_unsigned))
888 {
889 foreach (array_keys($this->_unsigned) as $key)
890 {
891 if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
892 {
893 $field['unsigned'] = ' UNSIGNED';
894 return;
895 }
896 elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
897 {
898 $field['type'] = $key;
899 return;
900 }
901 }
902
903 return;
904 }
905
906 $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
907 }
908
909 // --------------------------------------------------------------------
910
911 /**
912 * Field attribute DEFAULT
913 *
914 * @param array &$attributes
915 * @param array &$field
916 * @return void
917 */
918 protected function _attr_default(&$attributes, &$field)
919 {
920 if ($this->_default === FALSE)
921 {
922 return;
923 }
924
925 if (array_key_exists('DEFAULT', $attributes))
926 {
927 if ($attributes['DEFAULT'] === NULL)
928 {
929 $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
930
931 // Override the NULL attribute if that's our default
932 $attributes['NULL'] = NULL;
933 $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
934 }
935 else
936 {
937 $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
938 }
939 }
940 }
941
942 // --------------------------------------------------------------------
943
944 /**
945 * Field attribute UNIQUE
946 *
947 * @param array &$attributes
948 * @param array &$field
949 * @return void
950 */
951 protected function _attr_unique(&$attributes, &$field)
952 {
953 if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
954 {
955 $field['unique'] = ' UNIQUE';
956 }
957 }
958
959 // --------------------------------------------------------------------
960
961 /**
962 * Field attribute AUTO_INCREMENT
963 *
964 * @param array &$attributes
965 * @param array &$field
966 * @return void
967 */
968 protected function _attr_auto_increment(&$attributes, &$field)
969 {
970 if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
971 {
972 $field['auto_increment'] = ' AUTO_INCREMENT';
973 }
974 }
975
976 // --------------------------------------------------------------------
977
978 /**
979 * Process primary keys
980 *
981 * @param string $table Table name
982 * @return string
983 */
984 protected function _process_primary_keys($table)
985 {
986 $sql = '';
987
988 for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
989 {
990 if ( ! isset($this->fields[$this->primary_keys[$i]]))
991 {
992 unset($this->primary_keys[$i]);
993 }
994 }
995
996 if (count($this->primary_keys) > 0)
997 {
998 $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
999 .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
1000 }
1001
1002 return $sql;
1003 }
1004
1005 // --------------------------------------------------------------------
1006
1007 /**
1008 * Process indexes
1009 *
1010 * @param string $table
1011 * @return string
1012 */
Andrey Andreev35451022012-11-25 17:20:04 +02001013 protected function _process_indexes($table)
Andrey Andreeva287a342012-11-05 23:19:59 +02001014 {
Andrey Andreeva287a342012-11-05 23:19:59 +02001015 $sqls = array();
1016
1017 for ($i = 0, $c = count($this->keys); $i < $c; $i++)
1018 {
Andrey Andreev35451022012-11-25 17:20:04 +02001019 if (is_array($this->keys[$i]))
1020 {
1021 for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
1022 {
1023 if ( ! isset($this->fields[$this->keys[$i][$i2]]))
1024 {
1025 unset($this->keys[$i][$i2]);
1026 continue;
1027 }
1028 }
1029 }
1030 elseif ( ! isset($this->fields[$this->keys[$i]]))
Andrey Andreeva287a342012-11-05 23:19:59 +02001031 {
1032 unset($this->keys[$i]);
1033 continue;
1034 }
1035
1036 is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
1037
mjnaderid3a6ca22013-12-19 01:35:57 +03301038 $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
1039 .' ON '.$this->db->escape_identifiers($table)
Andrey Andreeva287a342012-11-05 23:19:59 +02001040 .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
1041 }
1042
1043 return $sqls;
1044 }
1045
1046 // --------------------------------------------------------------------
1047
1048 /**
Derek Allard2067d1a2008-11-13 22:59:24 +00001049 * Reset
1050 *
1051 * Resets table creation vars
1052 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001053 * @return void
1054 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +00001055 protected function _reset()
Derek Allard2067d1a2008-11-13 22:59:24 +00001056 {
Andrey Andreev24276a32012-01-08 02:44:38 +02001057 $this->fields = $this->keys = $this->primary_keys = array();
Derek Allard2067d1a2008-11-13 22:59:24 +00001058 }
1059
1060}
1061
1062/* End of file DB_forge.php */
Timothy Warren215890b2012-03-20 09:38:16 -04001063/* Location: ./system/database/DB_forge.php */