blob: 0317489f670c2ca71a592b2b2642c779cdc2c057 [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 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +02007 * This content is released under the MIT License (MIT)
Andrey Andreev24276a32012-01-08 02:44:38 +02008 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +02009 * Copyright (c) 2014, British Columbia Institute of Technology
Andrey Andreev24276a32012-01-08 02:44:38 +020010 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020011 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
Derek Jonesf4a4bd82011-10-20 12:18:42 -050017 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020018 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 *
29 * @package CodeIgniter
30 * @author EllisLab Dev Team
darwinel871754a2014-02-11 17:34:57 +010031 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020032 * @copyright Copyright (c) 2014, British Columbia Institute of Technology (http://bcit.ca/)
33 * @license http://opensource.org/licenses/MIT MIT License
34 * @link http://codeigniter.com
35 * @since Version 1.0.0
Derek Allard2067d1a2008-11-13 22:59:24 +000036 * @filesource
37 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020038defined('BASEPATH') OR exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +000039
Derek Allard2067d1a2008-11-13 22:59:24 +000040/**
Andrey Andreevd947eba2012-04-09 14:58:28 +030041 * Database Forge Class
Derek Allard2067d1a2008-11-13 22:59:24 +000042 *
43 * @category Database
Derek Jonesf4a4bd82011-10-20 12:18:42 -050044 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000045 * @link http://codeigniter.com/user_guide/database/
46 */
Timothy Warren833d5042012-03-19 16:12:03 -040047abstract class CI_DB_forge {
Derek Allard2067d1a2008-11-13 22:59:24 +000048
Andrey Andreevae85eb42012-11-02 01:42:31 +020049 /**
Andrey Andreeva287a342012-11-05 23:19:59 +020050 * Database object
51 *
52 * @var object
53 */
Andrey Andreeveaa60c72012-11-06 01:11:22 +020054 protected $db;
Andrey Andreeva287a342012-11-05 23:19:59 +020055
56 /**
Andrey Andreevae85eb42012-11-02 01:42:31 +020057 * Fields data
58 *
59 * @var array
60 */
Andrey Andreev24276a32012-01-08 02:44:38 +020061 public $fields = array();
Andrey Andreevae85eb42012-11-02 01:42:31 +020062
63 /**
64 * Keys data
65 *
66 * @var array
67 */
Andrey Andreev24276a32012-01-08 02:44:38 +020068 public $keys = array();
Andrey Andreevae85eb42012-11-02 01:42:31 +020069
70 /**
71 * Primary Keys data
72 *
73 * @var array
74 */
Andrey Andreev24276a32012-01-08 02:44:38 +020075 public $primary_keys = array();
Andrey Andreevae85eb42012-11-02 01:42:31 +020076
77 /**
78 * Database character set
79 *
80 * @var string
81 */
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030082 public $db_char_set = '';
Derek Allard2067d1a2008-11-13 22:59:24 +000083
Andrey Andreevae85eb42012-11-02 01:42:31 +020084 // --------------------------------------------------------------------
85
86 /**
87 * CREATE DATABASE statement
88 *
89 * @var string
90 */
Andrey Andreevd947eba2012-04-09 14:58:28 +030091 protected $_create_database = 'CREATE DATABASE %s';
Andrey Andreevae85eb42012-11-02 01:42:31 +020092
93 /**
94 * DROP DATABASE statement
95 *
96 * @var string
97 */
Andrey Andreevd947eba2012-04-09 14:58:28 +030098 protected $_drop_database = 'DROP DATABASE %s';
Andrey Andreevae85eb42012-11-02 01:42:31 +020099
100 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200101 * CREATE TABLE statement
Andrey Andreevae85eb42012-11-02 01:42:31 +0200102 *
103 * @var string
104 */
Andrey Andreeva287a342012-11-05 23:19:59 +0200105 protected $_create_table = "%s %s (%s\n)";
106
107 /**
108 * CREATE TABLE IF statement
109 *
110 * @var string
111 */
112 protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
113
114 /**
115 * CREATE TABLE keys flag
116 *
117 * Whether table keys are created from within the
118 * CREATE TABLE statement.
119 *
120 * @var bool
121 */
122 protected $_create_table_keys = FALSE;
123
124 /**
125 * DROP TABLE IF EXISTS statement
126 *
127 * @var string
128 */
129 protected $_drop_table_if = 'DROP TABLE IF EXISTS';
Andrey Andreevae85eb42012-11-02 01:42:31 +0200130
131 /**
132 * RENAME TABLE statement
133 *
134 * @var string
135 */
Andrey Andreeva287a342012-11-05 23:19:59 +0200136 protected $_rename_table = 'ALTER TABLE %s RENAME TO %s;';
137
138 /**
139 * UNSIGNED support
140 *
141 * @var bool|array
142 */
143 protected $_unsigned = TRUE;
144
145 /**
146 * NULL value representatin in CREATE/ALTER TABLE statements
147 *
148 * @var string
149 */
150 protected $_null = '';
151
152 /**
153 * DEFAULT value representation in CREATE/ALTER TABLE statements
154 *
155 * @var string
156 */
157 protected $_default = ' DEFAULT ';
Andrey Andreevd947eba2012-04-09 14:58:28 +0300158
Zachary Flower24fbc612014-11-02 21:50:15 -0700159 /**
160 * COMMENT value representation in CREATE/ALTER TABLE statements
161 *
162 * @var string
163 */
164 protected $_comment = ' COMMENT ';
165
Andrey Andreevae85eb42012-11-02 01:42:31 +0200166 // --------------------------------------------------------------------
167
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300168 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200169 * Class constructor
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300170 *
Andrey Andreeveaa60c72012-11-06 01:11:22 +0200171 * @param object &$db Database object
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300172 * @return void
173 */
Andrey Andreeveaa60c72012-11-06 01:11:22 +0200174 public function __construct(&$db)
Derek Allard2067d1a2008-11-13 22:59:24 +0000175 {
Andrey Andreeveaa60c72012-11-06 01:11:22 +0200176 $this->db =& $db;
Andrey Andreev24276a32012-01-08 02:44:38 +0200177 log_message('debug', 'Database Forge Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000178 }
179
180 // --------------------------------------------------------------------
181
182 /**
183 * Create database
184 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200185 * @param string $db_name
Derek Allard2067d1a2008-11-13 22:59:24 +0000186 * @return bool
187 */
Andrey Andreev24276a32012-01-08 02:44:38 +0200188 public function create_database($db_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000189 {
Andrey Andreevd947eba2012-04-09 14:58:28 +0300190 if ($this->_create_database === FALSE)
191 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200192 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300193 }
194 elseif ( ! $this->db->query(sprintf($this->_create_database, $db_name, $this->db->char_set, $this->db->dbcollat)))
195 {
196 return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
197 }
198
Andrey Andreev5d281762012-06-11 22:05:40 +0300199 if ( ! empty($this->db->data_cache['db_names']))
200 {
201 $this->db->data_cache['db_names'][] = $db_name;
202 }
203
Andrey Andreevd947eba2012-04-09 14:58:28 +0300204 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000205 }
206
207 // --------------------------------------------------------------------
208
209 /**
210 * Drop database
211 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200212 * @param string $db_name
Derek Allard2067d1a2008-11-13 22:59:24 +0000213 * @return bool
214 */
Andrey Andreev24276a32012-01-08 02:44:38 +0200215 public function drop_database($db_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000216 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100217 if ($db_name === '')
Andrey Andreevd947eba2012-04-09 14:58:28 +0300218 {
219 show_error('A table name is required for that operation.');
220 return FALSE;
221 }
222 elseif ($this->_drop_database === FALSE)
223 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200224 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300225 }
226 elseif ( ! $this->db->query(sprintf($this->_drop_database, $db_name)))
227 {
228 return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
229 }
230
Andrey Andreev5d281762012-06-11 22:05:40 +0300231 if ( ! empty($this->db->data_cache['db_names']))
232 {
233 $key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
234 if ($key !== FALSE)
235 {
236 unset($this->db->data_cache['db_names'][$key]);
237 }
238 }
239
Andrey Andreevd947eba2012-04-09 14:58:28 +0300240 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000241 }
242
243 // --------------------------------------------------------------------
244
245 /**
246 * Add Key
247 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200248 * @param string $key
249 * @param bool $primary
Andrey Andreevd8dba5d2012-12-17 15:42:01 +0200250 * @return CI_DB_forge
Derek Allard2067d1a2008-11-13 22:59:24 +0000251 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000252 public function add_key($key = '', $primary = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000253 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200254 if (empty($key))
255 {
256 show_error('Key information is required for that operation.');
257 }
258
Andrey Andreevd743cdb2012-11-06 00:00:01 +0200259 if ($primary === TRUE && is_array($key))
Derek Allard2067d1a2008-11-13 22:59:24 +0000260 {
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500261 foreach ($key as $one)
Derek Allard2067d1a2008-11-13 22:59:24 +0000262 {
263 $this->add_key($one, $primary);
264 }
Barry Mienydd671972010-10-04 16:33:58 +0200265
Andrey Andreeva287a342012-11-05 23:19:59 +0200266 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000267 }
Barry Mienydd671972010-10-04 16:33:58 +0200268
Derek Allard2067d1a2008-11-13 22:59:24 +0000269 if ($primary === TRUE)
270 {
271 $this->primary_keys[] = $key;
272 }
273 else
274 {
275 $this->keys[] = $key;
276 }
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000277
278 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000279 }
280
281 // --------------------------------------------------------------------
282
283 /**
284 * Add Field
285 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200286 * @param array $field
Andrew Podner4296a652012-12-17 07:51:15 -0500287 * @return CI_DB_forge
Derek Allard2067d1a2008-11-13 22:59:24 +0000288 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000289 public function add_field($field = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000290 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200291 if (empty($field))
Derek Allard2067d1a2008-11-13 22:59:24 +0000292 {
293 show_error('Field information is required.');
294 }
Barry Mienydd671972010-10-04 16:33:58 +0200295
Derek Allard2067d1a2008-11-13 22:59:24 +0000296 if (is_string($field))
297 {
Andrey Andreev24276a32012-01-08 02:44:38 +0200298 if ($field === 'id')
Derek Allard2067d1a2008-11-13 22:59:24 +0000299 {
300 $this->add_field(array(
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000301 'id' => array(
302 'type' => 'INT',
303 'constraint' => 9,
304 'auto_increment' => TRUE
305 )
306 ));
Derek Allard2067d1a2008-11-13 22:59:24 +0000307 $this->add_key('id', TRUE);
308 }
309 else
310 {
311 if (strpos($field, ' ') === FALSE)
312 {
313 show_error('Field information is required for that operation.');
314 }
Barry Mienydd671972010-10-04 16:33:58 +0200315
Derek Allard2067d1a2008-11-13 22:59:24 +0000316 $this->fields[] = $field;
317 }
318 }
Barry Mienydd671972010-10-04 16:33:58 +0200319
Derek Allard2067d1a2008-11-13 22:59:24 +0000320 if (is_array($field))
321 {
322 $this->fields = array_merge($this->fields, $field);
323 }
Andrey Andreev24276a32012-01-08 02:44:38 +0200324
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000325 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000326 }
327
328 // --------------------------------------------------------------------
329
330 /**
331 * Create Table
332 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200333 * @param string $table Table name
334 * @param bool $if_not_exists Whether to add IF NOT EXISTS condition
Andrey Andreev27f798b2014-01-20 18:19:13 +0200335 * @param array $attributes Associative array of table attributes
Derek Allard2067d1a2008-11-13 22:59:24 +0000336 * @return bool
337 */
Andrey Andreev27f798b2014-01-20 18:19:13 +0200338 public function create_table($table = '', $if_not_exists = FALSE, array $attributes = array())
Barry Mienydd671972010-10-04 16:33:58 +0200339 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100340 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000341 {
342 show_error('A table name is required for that operation.');
343 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200344 else
345 {
346 $table = $this->db->dbprefix.$table;
347 }
Barry Mienydd671972010-10-04 16:33:58 +0200348
Andrey Andreev24276a32012-01-08 02:44:38 +0200349 if (count($this->fields) === 0)
Barry Mienydd671972010-10-04 16:33:58 +0200350 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000351 show_error('Field information is required.');
352 }
353
Andrey Andreev27f798b2014-01-20 18:19:13 +0200354 $sql = $this->_create_table($table, $if_not_exists, $attributes);
Andrey Andreev5d281762012-06-11 22:05:40 +0300355
356 if (is_bool($sql))
357 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200358 $this->_reset();
359 if ($sql === FALSE)
360 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200361 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200362 }
Andrey Andreev5d281762012-06-11 22:05:40 +0300363 }
364
Andrey Andreeva287a342012-11-05 23:19:59 +0200365 if (($result = $this->db->query($sql)) !== FALSE)
Andrey Andreev5d281762012-06-11 22:05:40 +0300366 {
Andrey Andreeva287a342012-11-05 23:19:59 +0200367 empty($this->db->data_cache['table_names']) OR $this->db->data_cache['table_names'][] = $table;
368
369 // Most databases don't support creating indexes from within the CREATE TABLE statement
370 if ( ! empty($this->keys))
371 {
372 for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
373 {
374 $this->db->query($sqls[$i]);
375 }
376 }
Andrey Andreev5d281762012-06-11 22:05:40 +0300377 }
378
Andrey Andreeva287a342012-11-05 23:19:59 +0200379 $this->_reset();
Andrey Andreev5d281762012-06-11 22:05:40 +0300380 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000381 }
382
383 // --------------------------------------------------------------------
384
385 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200386 * Create Table
387 *
388 * @param string $table Table name
389 * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition
Andrey Andreev27f798b2014-01-20 18:19:13 +0200390 * @param array $attributes Associative array of table attributes
Andrey Andreeva287a342012-11-05 23:19:59 +0200391 * @return mixed
392 */
Andrey Andreev27f798b2014-01-20 18:19:13 +0200393 protected function _create_table($table, $if_not_exists, $attributes)
Andrey Andreeva287a342012-11-05 23:19:59 +0200394 {
395 if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
396 {
397 if ($this->db->table_exists($table))
398 {
399 return TRUE;
400 }
401 else
402 {
403 $if_not_exists = FALSE;
404 }
405 }
406
407 $sql = ($if_not_exists)
408 ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table))
409 : 'CREATE TABLE';
410
411 $columns = $this->_process_fields(TRUE);
412 for ($i = 0, $c = count($columns); $i < $c; $i++)
413 {
414 $columns[$i] = ($columns[$i]['_literal'] !== FALSE)
415 ? "\n\t".$columns[$i]['_literal']
416 : "\n\t".$this->_process_column($columns[$i]);
417 }
418
419 $columns = implode(',', $columns)
420 .$this->_process_primary_keys($table);
421
422 // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
423 if ($this->_create_table_keys === TRUE)
424 {
Andrey Andreev35451022012-11-25 17:20:04 +0200425 $columns .= $this->_process_indexes($table);
Andrey Andreeva287a342012-11-05 23:19:59 +0200426 }
427
428 // _create_table will usually have the following format: "%s %s (%s\n)"
Andrey Andreevaaca5cb2014-03-31 17:20:55 +0300429 $sql = sprintf($this->_create_table.'%s',
Andrey Andreeva287a342012-11-05 23:19:59 +0200430 $sql,
431 $this->db->escape_identifiers($table),
Andrey Andreev27f798b2014-01-20 18:19:13 +0200432 $columns,
433 $this->_create_table_attr($attributes)
Andrey Andreeva287a342012-11-05 23:19:59 +0200434 );
435
436 return $sql;
437 }
438
439 // --------------------------------------------------------------------
440
441 /**
Andrey Andreev27f798b2014-01-20 18:19:13 +0200442 * CREATE TABLE attributes
443 *
444 * @param array $attributes Associative array of table attributes
445 * @return string
446 */
447 protected function _create_table_attr($attributes)
448 {
449 $sql = '';
450
451 foreach (array_keys($attributes) as $key)
452 {
453 if (is_string($key))
454 {
455 $sql .= ' '.strtoupper($key).' '.$attributes[$key];
456 }
457 }
458
459 return $sql;
460 }
461
462 // --------------------------------------------------------------------
463
464 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000465 * Drop Table
466 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200467 * @param string $table_name Table name
468 * @param bool $if_exists Whether to add an IF EXISTS condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000469 * @return bool
470 */
Andrey Andreeva287a342012-11-05 23:19:59 +0200471 public function drop_table($table_name, $if_exists = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000472 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100473 if ($table_name === '')
Andrey Andreevd947eba2012-04-09 14:58:28 +0300474 {
475 return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
476 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200477
478 $query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists);
479 if ($query === FALSE)
Andrey Andreevd947eba2012-04-09 14:58:28 +0300480 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200481 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreevd947eba2012-04-09 14:58:28 +0300482 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200483 elseif ($query === TRUE)
484 {
485 return TRUE;
486 }
Andrey Andreevd947eba2012-04-09 14:58:28 +0300487
Andrey Andreeva287a342012-11-05 23:19:59 +0200488 $query = $this->db->query($query);
Andrey Andreev5d281762012-06-11 22:05:40 +0300489
490 // Update table list cache
Andrey Andreeva287a342012-11-05 23:19:59 +0200491 if ($query && ! empty($this->db->data_cache['table_names']))
Andrey Andreev5d281762012-06-11 22:05:40 +0300492 {
493 $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
494 if ($key !== FALSE)
495 {
496 unset($this->db->data_cache['table_names'][$key]);
497 }
498 }
499
Andrey Andreeva287a342012-11-05 23:19:59 +0200500 return $query;
501 }
502
503 // --------------------------------------------------------------------
504
505 /**
506 * Drop Table
507 *
508 * Generates a platform-specific DROP TABLE string
509 *
510 * @param string $table Table name
511 * @param bool $if_exists Whether to add an IF EXISTS condition
512 * @return string
513 */
514 protected function _drop_table($table, $if_exists)
515 {
516 $sql = 'DROP TABLE';
517
518 if ($if_exists)
519 {
520 if ($this->_drop_table_if === FALSE)
521 {
522 if ( ! $this->db->table_exists($table))
523 {
524 return TRUE;
525 }
526 }
527 else
528 {
529 $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
530 }
531 }
532
533 return $sql.' '.$this->db->escape_identifiers($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000534 }
535
536 // --------------------------------------------------------------------
537
538 /**
539 * Rename Table
540 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200541 * @param string $table_name Old table name
542 * @param string $new_table_name New table name
Derek Allard2067d1a2008-11-13 22:59:24 +0000543 * @return bool
544 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000545 public function rename_table($table_name, $new_table_name)
Derek Allard2067d1a2008-11-13 22:59:24 +0000546 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100547 if ($table_name === '' OR $new_table_name === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000548 {
549 show_error('A table name is required for that operation.');
Andrey Andreevd947eba2012-04-09 14:58:28 +0300550 return FALSE;
551 }
552 elseif ($this->_rename_table === FALSE)
553 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200554 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000555 }
Barry Mienydd671972010-10-04 16:33:58 +0200556
Andrey Andreev5d281762012-06-11 22:05:40 +0300557 $result = $this->db->query(sprintf($this->_rename_table,
Andrey Andreevd947eba2012-04-09 14:58:28 +0300558 $this->db->escape_identifiers($this->db->dbprefix.$table_name),
559 $this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
560 );
Andrey Andreev5d281762012-06-11 22:05:40 +0300561
562 if ($result && ! empty($this->db->data_cache['table_names']))
563 {
564 $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
565 if ($key !== FALSE)
566 {
567 $this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
568 }
569 }
570
571 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000572 }
573
574 // --------------------------------------------------------------------
575
576 /**
577 * Column Add
578 *
Andrey Andreevb67277b2012-11-12 12:51:14 +0200579 * @todo Remove deprecated $_after option in 3.1+
Andrey Andreeva287a342012-11-05 23:19:59 +0200580 * @param string $table Table name
581 * @param array $field Column definition
Andrey Andreevb67277b2012-11-12 12:51:14 +0200582 * @param string $_after Column for AFTER clause (deprecated)
Derek Allard2067d1a2008-11-13 22:59:24 +0000583 * @return bool
584 */
Andrey Andreevb67277b2012-11-12 12:51:14 +0200585 public function add_column($table = '', $field = array(), $_after = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000586 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100587 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000588 {
589 show_error('A table name is required for that operation.');
590 }
591
Andrey Andreeva287a342012-11-05 23:19:59 +0200592 // Work-around for literal column definitions
593 if ( ! is_array($field))
594 {
595 $field = array($field);
596 }
597
Andrey Andreev24276a32012-01-08 02:44:38 +0200598 foreach (array_keys($field) as $k)
Barry Mienydd671972010-10-04 16:33:58 +0200599 {
Andrey Andreevb67277b2012-11-12 12:51:14 +0200600 // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
601 if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
602 {
603 $field[$k]['after'] = $_after;
604 }
605
Barry Mienydd671972010-10-04 16:33:58 +0200606 $this->add_field(array($k => $field[$k]));
Andrey Andreeva287a342012-11-05 23:19:59 +0200607 }
Robin Sowell8a54ef22009-03-04 14:49:53 +0000608
Andrey Andreeva287a342012-11-05 23:19:59 +0200609 $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
610 $this->_reset();
611 if ($sqls === FALSE)
612 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200613 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200614 }
Barry Mienydd671972010-10-04 16:33:58 +0200615
Andrey Andreeva287a342012-11-05 23:19:59 +0200616 for ($i = 0, $c = count($sqls); $i < $c; $i++)
617 {
Andrey Andreev137a7422012-11-05 23:46:44 +0200618 if ($this->db->query($sqls[$i]) === FALSE)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000619 {
620 return FALSE;
621 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000622 }
Barry Mienydd671972010-10-04 16:33:58 +0200623
Robin Sowell8a54ef22009-03-04 14:49:53 +0000624 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000625 }
626
627 // --------------------------------------------------------------------
628
629 /**
630 * Column Drop
631 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200632 * @param string $table Table name
633 * @param string $column_name Column name
Derek Allard2067d1a2008-11-13 22:59:24 +0000634 * @return bool
635 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000636 public function drop_column($table = '', $column_name = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000637 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100638 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000639 {
640 show_error('A table name is required for that operation.');
641 }
642
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100643 if ($column_name === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000644 {
645 show_error('A column name is required for that operation.');
646 }
647
Andrey Andreeva287a342012-11-05 23:19:59 +0200648 $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
649 if ($sql === FALSE)
650 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200651 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200652 }
653
654 return $this->db->query($sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000655 }
656
657 // --------------------------------------------------------------------
658
659 /**
660 * Column Modify
661 *
Andrey Andreeva287a342012-11-05 23:19:59 +0200662 * @param string $table Table name
663 * @param string $field Column definition
Derek Allard2067d1a2008-11-13 22:59:24 +0000664 * @return bool
665 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +0000666 public function modify_column($table = '', $field = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000667 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100668 if ($table === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000669 {
670 show_error('A table name is required for that operation.');
671 }
672
Andrey Andreeva287a342012-11-05 23:19:59 +0200673 // Work-around for literal column definitions
674 if ( ! is_array($field))
675 {
676 $field = array($field);
677 }
678
Andrey Andreev24276a32012-01-08 02:44:38 +0200679 foreach (array_keys($field) as $k)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000680 {
681 $this->add_field(array($k => $field[$k]));
Andrey Andreeva287a342012-11-05 23:19:59 +0200682 }
Barry Mienydd671972010-10-04 16:33:58 +0200683
Andrey Andreeva287a342012-11-05 23:19:59 +0200684 if (count($this->fields) === 0)
685 {
686 show_error('Field information is required.');
687 }
Barry Mienydd671972010-10-04 16:33:58 +0200688
Andrey Andreev7ade8b72012-11-22 13:12:22 +0200689 $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
Andrey Andreeva287a342012-11-05 23:19:59 +0200690 $this->_reset();
691 if ($sqls === FALSE)
692 {
Andrey Andreev8d3afde2012-11-06 12:53:47 +0200693 return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200694 }
695
696 for ($i = 0, $c = count($sqls); $i < $c; $i++)
697 {
Andrey Andreev137a7422012-11-05 23:46:44 +0200698 if ($this->db->query($sqls[$i]) === FALSE)
Robin Sowell8a54ef22009-03-04 14:49:53 +0000699 {
700 return FALSE;
701 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000702 }
Barry Mienydd671972010-10-04 16:33:58 +0200703
Robin Sowell8a54ef22009-03-04 14:49:53 +0000704 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000705 }
706
707 // --------------------------------------------------------------------
708
709 /**
Andrey Andreeva287a342012-11-05 23:19:59 +0200710 * ALTER TABLE
711 *
712 * @param string $alter_type ALTER type
713 * @param string $table Table name
714 * @param mixed $field Column definition
715 * @return string|string[]
716 */
717 protected function _alter_table($alter_type, $table, $field)
718 {
719 $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
720
721 // DROP has everything it needs now.
722 if ($alter_type === 'DROP')
723 {
724 return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
725 }
726
Andrey Andreev13f6eab2013-03-15 10:56:55 +0200727 $sql .= ($alter_type === 'ADD')
728 ? 'ADD '
729 : $alter_type.' COLUMN ';
730
Andrey Andreeva287a342012-11-05 23:19:59 +0200731 $sqls = array();
Andrey Andreev13f6eab2013-03-15 10:56:55 +0200732 for ($i = 0, $c = count($field); $i < $c; $i++)
Andrey Andreeva287a342012-11-05 23:19:59 +0200733 {
734 $sqls[] = $sql
735 .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
736 }
737
738 return $sqls;
739 }
740
741 // --------------------------------------------------------------------
742
743 /**
744 * Process fields
745 *
746 * @param bool $create_table
747 * @return array
748 */
749 protected function _process_fields($create_table = FALSE)
750 {
751 $fields = array();
752
753 foreach ($this->fields as $key => $attributes)
754 {
755 if (is_int($key) && ! is_array($attributes))
756 {
757 $fields[] = array('_literal' => $attributes);
758 continue;
759 }
760
761 $attributes = array_change_key_case($attributes, CASE_UPPER);
762
763 if ($create_table === TRUE && empty($attributes['TYPE']))
764 {
765 continue;
766 }
767
Andrey Andreev13943042014-03-17 11:50:45 +0200768 isset($attributes['TYPE']) && $this->_attr_type($attributes);
Andrey Andreeva287a342012-11-05 23:19:59 +0200769
770 $field = array(
Andrey Andreev13943042014-03-17 11:50:45 +0200771 'name' => $key,
772 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
773 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
774 'length' => '',
775 'unsigned' => '',
776 'null' => '',
777 'unique' => '',
778 'default' => '',
779 'auto_increment' => '',
Zachary Flowere59347d2014-11-03 08:34:12 -0700780 'comment' => '',
Andrey Andreev13943042014-03-17 11:50:45 +0200781 '_literal' => FALSE
Andrey Andreeva287a342012-11-05 23:19:59 +0200782 );
783
Andrey Andreev13943042014-03-17 11:50:45 +0200784 isset($attributes['TYPE']) && $this->_attr_unsigned($attributes, $field);
785
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200786 if ($create_table === FALSE)
787 {
788 if (isset($attributes['AFTER']))
789 {
Andrey Andreev96185a32013-10-28 16:04:02 +0200790 $field['after'] = $attributes['AFTER'];
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200791 }
792 elseif (isset($attributes['FIRST']))
793 {
794 $field['first'] = (bool) $attributes['FIRST'];
795 }
796 }
797
Andrey Andreeva287a342012-11-05 23:19:59 +0200798 $this->_attr_default($attributes, $field);
799
800 if (isset($attributes['NULL']))
801 {
802 if ($attributes['NULL'] === TRUE)
803 {
804 $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
805 }
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200806 else
Andrey Andreeva287a342012-11-05 23:19:59 +0200807 {
808 $field['null'] = ' NOT NULL';
809 }
810 }
Andrey Andreev5d69a6e2013-10-28 15:34:47 +0200811 elseif ($create_table === TRUE)
812 {
813 $field['null'] = ' NOT NULL';
814 }
Andrey Andreeva287a342012-11-05 23:19:59 +0200815
816 $this->_attr_auto_increment($attributes, $field);
817 $this->_attr_unique($attributes, $field);
Zachary Flower12ee7a12014-11-03 08:38:41 -0700818 $this->_attr_comment($attributes, $field);
Andrey Andreeva287a342012-11-05 23:19:59 +0200819
820 if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
821 {
822 switch (strtoupper($attributes['TYPE']))
823 {
824 case 'ENUM':
825 case 'SET':
826 $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
Andrey Andreevc5a0af22014-03-10 10:29:43 +0200827 $field['length'] = is_array($attributes['CONSTRAINT'])
828 ? "('".implode("','", $attributes['CONSTRAINT'])."')"
829 : '('.$attributes['CONSTRAINT'].')';
Andrey Andreevfde170c2014-03-10 19:55:11 +0200830 break;
Andrey Andreeva287a342012-11-05 23:19:59 +0200831 default:
832 $field['length'] = is_array($attributes['CONSTRAINT'])
Andrey Andreevc5a0af22014-03-10 10:29:43 +0200833 ? '('.implode(',', $attributes['CONSTRAINT']).')'
834 : '('.$attributes['CONSTRAINT'].')';
Andrey Andreeva287a342012-11-05 23:19:59 +0200835 break;
836 }
837 }
838
839 $fields[] = $field;
840 }
841
842 return $fields;
843 }
844
845 // --------------------------------------------------------------------
846
847 /**
848 * Process column
849 *
850 * @param array $field
851 * @return string
852 */
853 protected function _process_column($field)
854 {
855 return $this->db->escape_identifiers($field['name'])
856 .' '.$field['type'].$field['length']
857 .$field['unsigned']
858 .$field['default']
859 .$field['null']
860 .$field['auto_increment']
Zachary Flower12ee7a12014-11-03 08:38:41 -0700861 .$field['unique']
862 .$field['comment'];
Andrey Andreeva287a342012-11-05 23:19:59 +0200863 }
864
865 // --------------------------------------------------------------------
866
867 /**
868 * Field attribute TYPE
869 *
870 * Performs a data type mapping between different databases.
871 *
872 * @param array &$attributes
873 * @return void
874 */
875 protected function _attr_type(&$attributes)
876 {
877 // Usually overriden by drivers
878 }
879
880 // --------------------------------------------------------------------
881
882 /**
883 * Field attribute UNSIGNED
884 *
885 * Depending on the _unsigned property value:
886 *
887 * - TRUE will always set $field['unsigned'] to 'UNSIGNED'
888 * - FALSE will always set $field['unsigned'] to ''
889 * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
890 * if $attributes['TYPE'] is found in the array
891 * - array(TYPE => UTYPE) will change $field['type'],
892 * from TYPE to UTYPE in case of a match
893 *
894 * @param array &$attributes
895 * @param array &$field
896 * @return void
897 */
898 protected function _attr_unsigned(&$attributes, &$field)
899 {
900 if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
901 {
902 return;
903 }
904
905 // Reset the attribute in order to avoid issues if we do type conversion
906 $attributes['UNSIGNED'] = FALSE;
907
908 if (is_array($this->_unsigned))
909 {
910 foreach (array_keys($this->_unsigned) as $key)
911 {
912 if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
913 {
914 $field['unsigned'] = ' UNSIGNED';
915 return;
916 }
917 elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
918 {
919 $field['type'] = $key;
920 return;
921 }
922 }
923
924 return;
925 }
926
927 $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
928 }
929
930 // --------------------------------------------------------------------
931
932 /**
933 * Field attribute DEFAULT
934 *
935 * @param array &$attributes
936 * @param array &$field
937 * @return void
938 */
939 protected function _attr_default(&$attributes, &$field)
940 {
941 if ($this->_default === FALSE)
942 {
943 return;
944 }
945
946 if (array_key_exists('DEFAULT', $attributes))
947 {
948 if ($attributes['DEFAULT'] === NULL)
949 {
950 $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
951
952 // Override the NULL attribute if that's our default
Andrey Andreev22ce2762014-08-15 11:59:16 +0300953 $attributes['NULL'] = TRUE;
Andrey Andreeva287a342012-11-05 23:19:59 +0200954 $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
955 }
956 else
957 {
958 $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
959 }
960 }
961 }
962
963 // --------------------------------------------------------------------
964
965 /**
966 * Field attribute UNIQUE
967 *
968 * @param array &$attributes
969 * @param array &$field
970 * @return void
971 */
972 protected function _attr_unique(&$attributes, &$field)
973 {
974 if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
975 {
976 $field['unique'] = ' UNIQUE';
977 }
978 }
979
980 // --------------------------------------------------------------------
981
982 /**
983 * Field attribute AUTO_INCREMENT
984 *
985 * @param array &$attributes
986 * @param array &$field
987 * @return void
988 */
989 protected function _attr_auto_increment(&$attributes, &$field)
990 {
991 if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
992 {
993 $field['auto_increment'] = ' AUTO_INCREMENT';
994 }
995 }
996
997 // --------------------------------------------------------------------
998
999 /**
Zachary Flower24fbc612014-11-02 21:50:15 -07001000 * Field attribute COMMENT
1001 *
1002 * @param array &$attributes
1003 * @param array &$field
1004 * @return void
1005 */
1006 protected function _attr_comment(&$attributes, &$field)
1007 {
1008 if ($this->_comment === FALSE)
1009 {
1010 return;
1011 }
1012
1013 if (!empty($attributes['COMMENT']))
1014 {
1015 $field['comment'] = $this->_default.$this->db->escape($attributes['COMMENT']);
1016 }
1017 }
1018
1019 // --------------------------------------------------------------------
1020
1021 /**
Andrey Andreeva287a342012-11-05 23:19:59 +02001022 * Process primary keys
1023 *
1024 * @param string $table Table name
1025 * @return string
1026 */
1027 protected function _process_primary_keys($table)
1028 {
1029 $sql = '';
1030
1031 for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
1032 {
1033 if ( ! isset($this->fields[$this->primary_keys[$i]]))
1034 {
1035 unset($this->primary_keys[$i]);
1036 }
1037 }
1038
1039 if (count($this->primary_keys) > 0)
1040 {
1041 $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
1042 .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
1043 }
1044
1045 return $sql;
1046 }
1047
1048 // --------------------------------------------------------------------
1049
1050 /**
1051 * Process indexes
1052 *
1053 * @param string $table
1054 * @return string
1055 */
Andrey Andreev35451022012-11-25 17:20:04 +02001056 protected function _process_indexes($table)
Andrey Andreeva287a342012-11-05 23:19:59 +02001057 {
Andrey Andreeva287a342012-11-05 23:19:59 +02001058 $sqls = array();
1059
1060 for ($i = 0, $c = count($this->keys); $i < $c; $i++)
1061 {
Andrey Andreev35451022012-11-25 17:20:04 +02001062 if (is_array($this->keys[$i]))
1063 {
1064 for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
1065 {
1066 if ( ! isset($this->fields[$this->keys[$i][$i2]]))
1067 {
1068 unset($this->keys[$i][$i2]);
1069 continue;
1070 }
1071 }
1072 }
1073 elseif ( ! isset($this->fields[$this->keys[$i]]))
Andrey Andreeva287a342012-11-05 23:19:59 +02001074 {
1075 unset($this->keys[$i]);
1076 continue;
1077 }
1078
1079 is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
1080
mjnaderid3a6ca22013-12-19 01:35:57 +03301081 $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
1082 .' ON '.$this->db->escape_identifiers($table)
Andrey Andreeva287a342012-11-05 23:19:59 +02001083 .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
1084 }
1085
1086 return $sqls;
1087 }
1088
1089 // --------------------------------------------------------------------
1090
1091 /**
Derek Allard2067d1a2008-11-13 22:59:24 +00001092 * Reset
1093 *
1094 * Resets table creation vars
1095 *
Derek Allard2067d1a2008-11-13 22:59:24 +00001096 * @return void
1097 */
Phil Sturgeona7de97e2011-12-31 18:41:08 +00001098 protected function _reset()
Derek Allard2067d1a2008-11-13 22:59:24 +00001099 {
Andrey Andreev24276a32012-01-08 02:44:38 +02001100 $this->fields = $this->keys = $this->primary_keys = array();
Derek Allard2067d1a2008-11-13 22:59:24 +00001101 }
1102
1103}
1104
1105/* End of file DB_forge.php */
Timothy Warren215890b2012-03-20 09:38:16 -04001106/* Location: ./system/database/DB_forge.php */