DB_forge.php 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
  10. *
  11. * 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:
  17. *
  18. * 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
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * Database Forge Class
  41. *
  42. * @category Database
  43. * @author EllisLab Dev Team
  44. * @link https://codeigniter.com/user_guide/database/
  45. */
  46. abstract class CI_DB_forge {
  47. /**
  48. * Database object
  49. *
  50. * @var object
  51. */
  52. protected $db;
  53. /**
  54. * Fields data
  55. *
  56. * @var array
  57. */
  58. public $fields = array();
  59. /**
  60. * Keys data
  61. *
  62. * @var array
  63. */
  64. public $keys = array();
  65. /**
  66. * Primary Keys data
  67. *
  68. * @var array
  69. */
  70. public $primary_keys = array();
  71. /**
  72. * Database character set
  73. *
  74. * @var string
  75. */
  76. public $db_char_set = '';
  77. // --------------------------------------------------------------------
  78. /**
  79. * CREATE DATABASE statement
  80. *
  81. * @var string
  82. */
  83. protected $_create_database = 'CREATE DATABASE %s';
  84. /**
  85. * DROP DATABASE statement
  86. *
  87. * @var string
  88. */
  89. protected $_drop_database = 'DROP DATABASE %s';
  90. /**
  91. * CREATE TABLE statement
  92. *
  93. * @var string
  94. */
  95. protected $_create_table = "%s %s (%s\n)";
  96. /**
  97. * CREATE TABLE IF statement
  98. *
  99. * @var string
  100. */
  101. protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
  102. /**
  103. * CREATE TABLE keys flag
  104. *
  105. * Whether table keys are created from within the
  106. * CREATE TABLE statement.
  107. *
  108. * @var bool
  109. */
  110. protected $_create_table_keys = FALSE;
  111. /**
  112. * DROP TABLE IF EXISTS statement
  113. *
  114. * @var string
  115. */
  116. protected $_drop_table_if = 'DROP TABLE IF EXISTS';
  117. /**
  118. * RENAME TABLE statement
  119. *
  120. * @var string
  121. */
  122. protected $_rename_table = 'ALTER TABLE %s RENAME TO %s;';
  123. /**
  124. * UNSIGNED support
  125. *
  126. * @var bool|array
  127. */
  128. protected $_unsigned = TRUE;
  129. /**
  130. * NULL value representation in CREATE/ALTER TABLE statements
  131. *
  132. * @var string
  133. */
  134. protected $_null = '';
  135. /**
  136. * DEFAULT value representation in CREATE/ALTER TABLE statements
  137. *
  138. * @var string
  139. */
  140. protected $_default = ' DEFAULT ';
  141. // --------------------------------------------------------------------
  142. /**
  143. * Class constructor
  144. *
  145. * @param object &$db Database object
  146. * @return void
  147. */
  148. public function __construct(&$db)
  149. {
  150. $this->db =& $db;
  151. log_message('info', 'Database Forge Class Initialized');
  152. }
  153. // --------------------------------------------------------------------
  154. /**
  155. * Create database
  156. *
  157. * @param string $db_name
  158. * @return bool
  159. */
  160. public function create_database($db_name)
  161. {
  162. if ($this->_create_database === FALSE)
  163. {
  164. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  165. }
  166. elseif ( ! $this->db->query(sprintf($this->_create_database, $this->db->escape_identifiers($db_name), $this->db->char_set, $this->db->dbcollat)))
  167. {
  168. return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
  169. }
  170. if ( ! empty($this->db->data_cache['db_names']))
  171. {
  172. $this->db->data_cache['db_names'][] = $db_name;
  173. }
  174. return TRUE;
  175. }
  176. // --------------------------------------------------------------------
  177. /**
  178. * Drop database
  179. *
  180. * @param string $db_name
  181. * @return bool
  182. */
  183. public function drop_database($db_name)
  184. {
  185. if ($this->_drop_database === FALSE)
  186. {
  187. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  188. }
  189. elseif ( ! $this->db->query(sprintf($this->_drop_database, $this->db->escape_identifiers($db_name))))
  190. {
  191. return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
  192. }
  193. if ( ! empty($this->db->data_cache['db_names']))
  194. {
  195. $key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
  196. if ($key !== FALSE)
  197. {
  198. unset($this->db->data_cache['db_names'][$key]);
  199. }
  200. }
  201. return TRUE;
  202. }
  203. // --------------------------------------------------------------------
  204. /**
  205. * Add Key
  206. *
  207. * @param string $key
  208. * @param bool $primary
  209. * @return CI_DB_forge
  210. */
  211. public function add_key($key, $primary = FALSE)
  212. {
  213. // DO NOT change this! This condition is only applicable
  214. // for PRIMARY keys because you can only have one such,
  215. // and therefore all fields you add to it will be included
  216. // in the same, composite PRIMARY KEY.
  217. //
  218. // It's not the same for regular indexes.
  219. if ($primary === TRUE && is_array($key))
  220. {
  221. foreach ($key as $one)
  222. {
  223. $this->add_key($one, $primary);
  224. }
  225. return $this;
  226. }
  227. if ($primary === TRUE)
  228. {
  229. $this->primary_keys[] = $key;
  230. }
  231. else
  232. {
  233. $this->keys[] = $key;
  234. }
  235. return $this;
  236. }
  237. // --------------------------------------------------------------------
  238. /**
  239. * Add Field
  240. *
  241. * @param array $field
  242. * @return CI_DB_forge
  243. */
  244. public function add_field($field)
  245. {
  246. if (is_string($field))
  247. {
  248. if ($field === 'id')
  249. {
  250. $this->add_field(array(
  251. 'id' => array(
  252. 'type' => 'INT',
  253. 'constraint' => 9,
  254. 'auto_increment' => TRUE
  255. )
  256. ));
  257. $this->add_key('id', TRUE);
  258. }
  259. else
  260. {
  261. if (strpos($field, ' ') === FALSE)
  262. {
  263. show_error('Field information is required for that operation.');
  264. }
  265. $this->fields[] = $field;
  266. }
  267. }
  268. if (is_array($field))
  269. {
  270. $this->fields = array_merge($this->fields, $field);
  271. }
  272. return $this;
  273. }
  274. // --------------------------------------------------------------------
  275. /**
  276. * Create Table
  277. *
  278. * @param string $table Table name
  279. * @param bool $if_not_exists Whether to add IF NOT EXISTS condition
  280. * @param array $attributes Associative array of table attributes
  281. * @return bool
  282. */
  283. public function create_table($table, $if_not_exists = FALSE, array $attributes = array())
  284. {
  285. if ($table === '')
  286. {
  287. show_error('A table name is required for that operation.');
  288. }
  289. else
  290. {
  291. $table = $this->db->dbprefix.$table;
  292. }
  293. if (count($this->fields) === 0)
  294. {
  295. show_error('Field information is required.');
  296. }
  297. $sql = $this->_create_table($table, $if_not_exists, $attributes);
  298. if (is_bool($sql))
  299. {
  300. $this->_reset();
  301. if ($sql === FALSE)
  302. {
  303. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  304. }
  305. }
  306. if (($result = $this->db->query($sql)) !== FALSE)
  307. {
  308. isset($this->db->data_cache['table_names']) && $this->db->data_cache['table_names'][] = $table;
  309. // Most databases don't support creating indexes from within the CREATE TABLE statement
  310. if ( ! empty($this->keys))
  311. {
  312. for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
  313. {
  314. $this->db->query($sqls[$i]);
  315. }
  316. }
  317. }
  318. $this->_reset();
  319. return $result;
  320. }
  321. // --------------------------------------------------------------------
  322. /**
  323. * Create Table
  324. *
  325. * @param string $table Table name
  326. * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition
  327. * @param array $attributes Associative array of table attributes
  328. * @return mixed
  329. */
  330. protected function _create_table($table, $if_not_exists, $attributes)
  331. {
  332. if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
  333. {
  334. if ($this->db->table_exists($table))
  335. {
  336. return TRUE;
  337. }
  338. $if_not_exists = FALSE;
  339. }
  340. $sql = ($if_not_exists)
  341. ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table))
  342. : 'CREATE TABLE';
  343. $columns = $this->_process_fields(TRUE);
  344. for ($i = 0, $c = count($columns); $i < $c; $i++)
  345. {
  346. $columns[$i] = ($columns[$i]['_literal'] !== FALSE)
  347. ? "\n\t".$columns[$i]['_literal']
  348. : "\n\t".$this->_process_column($columns[$i]);
  349. }
  350. $columns = implode(',', $columns)
  351. .$this->_process_primary_keys($table);
  352. // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
  353. if ($this->_create_table_keys === TRUE)
  354. {
  355. $columns .= $this->_process_indexes($table);
  356. }
  357. // _create_table will usually have the following format: "%s %s (%s\n)"
  358. $sql = sprintf($this->_create_table.'%s',
  359. $sql,
  360. $this->db->escape_identifiers($table),
  361. $columns,
  362. $this->_create_table_attr($attributes)
  363. );
  364. return $sql;
  365. }
  366. // --------------------------------------------------------------------
  367. /**
  368. * CREATE TABLE attributes
  369. *
  370. * @param array $attributes Associative array of table attributes
  371. * @return string
  372. */
  373. protected function _create_table_attr($attributes)
  374. {
  375. $sql = '';
  376. foreach (array_keys($attributes) as $key)
  377. {
  378. if (is_string($key))
  379. {
  380. $sql .= ' '.strtoupper($key).' '.$attributes[$key];
  381. }
  382. }
  383. return $sql;
  384. }
  385. // --------------------------------------------------------------------
  386. /**
  387. * Drop Table
  388. *
  389. * @param string $table_name Table name
  390. * @param bool $if_exists Whether to add an IF EXISTS condition
  391. * @return bool
  392. */
  393. public function drop_table($table_name, $if_exists = FALSE)
  394. {
  395. if ($table_name === '')
  396. {
  397. return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
  398. }
  399. if (($query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists)) === TRUE)
  400. {
  401. return TRUE;
  402. }
  403. $query = $this->db->query($query);
  404. // Update table list cache
  405. if ($query && ! empty($this->db->data_cache['table_names']))
  406. {
  407. $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
  408. if ($key !== FALSE)
  409. {
  410. unset($this->db->data_cache['table_names'][$key]);
  411. }
  412. }
  413. return $query;
  414. }
  415. // --------------------------------------------------------------------
  416. /**
  417. * Drop Table
  418. *
  419. * Generates a platform-specific DROP TABLE string
  420. *
  421. * @param string $table Table name
  422. * @param bool $if_exists Whether to add an IF EXISTS condition
  423. * @return mixed (Returns a platform-specific DROP table string, or TRUE to indicate there's nothing to do)
  424. */
  425. protected function _drop_table($table, $if_exists)
  426. {
  427. $sql = 'DROP TABLE';
  428. if ($if_exists)
  429. {
  430. if ($this->_drop_table_if === FALSE)
  431. {
  432. if ( ! $this->db->table_exists($table))
  433. {
  434. return TRUE;
  435. }
  436. }
  437. else
  438. {
  439. $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
  440. }
  441. }
  442. return $sql.' '.$this->db->escape_identifiers($table);
  443. }
  444. // --------------------------------------------------------------------
  445. /**
  446. * Rename Table
  447. *
  448. * @param string $table_name Old table name
  449. * @param string $new_table_name New table name
  450. * @return bool
  451. */
  452. public function rename_table($table_name, $new_table_name)
  453. {
  454. if ($table_name === '' OR $new_table_name === '')
  455. {
  456. show_error('A table name is required for that operation.');
  457. return FALSE;
  458. }
  459. elseif ($this->_rename_table === FALSE)
  460. {
  461. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  462. }
  463. $result = $this->db->query(sprintf($this->_rename_table,
  464. $this->db->escape_identifiers($this->db->dbprefix.$table_name),
  465. $this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
  466. );
  467. if ($result && ! empty($this->db->data_cache['table_names']))
  468. {
  469. $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
  470. if ($key !== FALSE)
  471. {
  472. $this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
  473. }
  474. }
  475. return $result;
  476. }
  477. // --------------------------------------------------------------------
  478. /**
  479. * Column Add
  480. *
  481. * @todo Remove deprecated $_after option in 3.1+
  482. * @param string $table Table name
  483. * @param array $field Column definition
  484. * @param string $_after Column for AFTER clause (deprecated)
  485. * @return bool
  486. */
  487. public function add_column($table, $field, $_after = NULL)
  488. {
  489. // Work-around for literal column definitions
  490. is_array($field) OR $field = array($field);
  491. foreach (array_keys($field) as $k)
  492. {
  493. // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
  494. if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
  495. {
  496. $field[$k]['after'] = $_after;
  497. }
  498. $this->add_field(array($k => $field[$k]));
  499. }
  500. $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
  501. $this->_reset();
  502. if ($sqls === FALSE)
  503. {
  504. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  505. }
  506. for ($i = 0, $c = count($sqls); $i < $c; $i++)
  507. {
  508. if ($this->db->query($sqls[$i]) === FALSE)
  509. {
  510. return FALSE;
  511. }
  512. }
  513. return TRUE;
  514. }
  515. // --------------------------------------------------------------------
  516. /**
  517. * Column Drop
  518. *
  519. * @param string $table Table name
  520. * @param string $column_name Column name
  521. * @return bool
  522. */
  523. public function drop_column($table, $column_name)
  524. {
  525. $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
  526. if ($sql === FALSE)
  527. {
  528. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  529. }
  530. return $this->db->query($sql);
  531. }
  532. // --------------------------------------------------------------------
  533. /**
  534. * Column Modify
  535. *
  536. * @param string $table Table name
  537. * @param string $field Column definition
  538. * @return bool
  539. */
  540. public function modify_column($table, $field)
  541. {
  542. // Work-around for literal column definitions
  543. is_array($field) OR $field = array($field);
  544. foreach (array_keys($field) as $k)
  545. {
  546. $this->add_field(array($k => $field[$k]));
  547. }
  548. if (count($this->fields) === 0)
  549. {
  550. show_error('Field information is required.');
  551. }
  552. $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
  553. $this->_reset();
  554. if ($sqls === FALSE)
  555. {
  556. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  557. }
  558. for ($i = 0, $c = count($sqls); $i < $c; $i++)
  559. {
  560. if ($this->db->query($sqls[$i]) === FALSE)
  561. {
  562. return FALSE;
  563. }
  564. }
  565. return TRUE;
  566. }
  567. // --------------------------------------------------------------------
  568. /**
  569. * ALTER TABLE
  570. *
  571. * @param string $alter_type ALTER type
  572. * @param string $table Table name
  573. * @param mixed $field Column definition
  574. * @return string|string[]
  575. */
  576. protected function _alter_table($alter_type, $table, $field)
  577. {
  578. $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
  579. // DROP has everything it needs now.
  580. if ($alter_type === 'DROP')
  581. {
  582. return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
  583. }
  584. $sql .= ($alter_type === 'ADD')
  585. ? 'ADD '
  586. : $alter_type.' COLUMN ';
  587. $sqls = array();
  588. for ($i = 0, $c = count($field); $i < $c; $i++)
  589. {
  590. $sqls[] = $sql
  591. .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
  592. }
  593. return $sqls;
  594. }
  595. // --------------------------------------------------------------------
  596. /**
  597. * Process fields
  598. *
  599. * @param bool $create_table
  600. * @return array
  601. */
  602. protected function _process_fields($create_table = FALSE)
  603. {
  604. $fields = array();
  605. foreach ($this->fields as $key => $attributes)
  606. {
  607. if (is_int($key) && ! is_array($attributes))
  608. {
  609. $fields[] = array('_literal' => $attributes);
  610. continue;
  611. }
  612. $attributes = array_change_key_case($attributes, CASE_UPPER);
  613. if ($create_table === TRUE && empty($attributes['TYPE']))
  614. {
  615. continue;
  616. }
  617. isset($attributes['TYPE']) && $this->_attr_type($attributes);
  618. $field = array(
  619. 'name' => $key,
  620. 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
  621. 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
  622. 'length' => '',
  623. 'unsigned' => '',
  624. 'null' => '',
  625. 'unique' => '',
  626. 'default' => '',
  627. 'auto_increment' => '',
  628. '_literal' => FALSE
  629. );
  630. isset($attributes['TYPE']) && $this->_attr_unsigned($attributes, $field);
  631. if ($create_table === FALSE)
  632. {
  633. if (isset($attributes['AFTER']))
  634. {
  635. $field['after'] = $attributes['AFTER'];
  636. }
  637. elseif (isset($attributes['FIRST']))
  638. {
  639. $field['first'] = (bool) $attributes['FIRST'];
  640. }
  641. }
  642. $this->_attr_default($attributes, $field);
  643. if (isset($attributes['NULL']))
  644. {
  645. if ($attributes['NULL'] === TRUE)
  646. {
  647. $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
  648. }
  649. else
  650. {
  651. $field['null'] = ' NOT NULL';
  652. }
  653. }
  654. elseif ($create_table === TRUE)
  655. {
  656. $field['null'] = ' NOT NULL';
  657. }
  658. $this->_attr_auto_increment($attributes, $field);
  659. $this->_attr_unique($attributes, $field);
  660. if (isset($attributes['COMMENT']))
  661. {
  662. $field['comment'] = $this->db->escape($attributes['COMMENT']);
  663. }
  664. if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
  665. {
  666. switch (strtoupper($attributes['TYPE']))
  667. {
  668. case 'ENUM':
  669. case 'SET':
  670. $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
  671. default:
  672. $field['length'] = is_array($attributes['CONSTRAINT'])
  673. ? '('.implode(',', $attributes['CONSTRAINT']).')'
  674. : '('.$attributes['CONSTRAINT'].')';
  675. break;
  676. }
  677. }
  678. $fields[] = $field;
  679. }
  680. return $fields;
  681. }
  682. // --------------------------------------------------------------------
  683. /**
  684. * Process column
  685. *
  686. * @param array $field
  687. * @return string
  688. */
  689. protected function _process_column($field)
  690. {
  691. return $this->db->escape_identifiers($field['name'])
  692. .' '.$field['type'].$field['length']
  693. .$field['unsigned']
  694. .$field['default']
  695. .$field['null']
  696. .$field['auto_increment']
  697. .$field['unique'];
  698. }
  699. // --------------------------------------------------------------------
  700. /**
  701. * Field attribute TYPE
  702. *
  703. * Performs a data type mapping between different databases.
  704. *
  705. * @param array &$attributes
  706. * @return void
  707. */
  708. protected function _attr_type(&$attributes)
  709. {
  710. // Usually overridden by drivers
  711. }
  712. // --------------------------------------------------------------------
  713. /**
  714. * Field attribute UNSIGNED
  715. *
  716. * Depending on the _unsigned property value:
  717. *
  718. * - TRUE will always set $field['unsigned'] to 'UNSIGNED'
  719. * - FALSE will always set $field['unsigned'] to ''
  720. * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
  721. * if $attributes['TYPE'] is found in the array
  722. * - array(TYPE => UTYPE) will change $field['type'],
  723. * from TYPE to UTYPE in case of a match
  724. *
  725. * @param array &$attributes
  726. * @param array &$field
  727. * @return void
  728. */
  729. protected function _attr_unsigned(&$attributes, &$field)
  730. {
  731. if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
  732. {
  733. return;
  734. }
  735. // Reset the attribute in order to avoid issues if we do type conversion
  736. $attributes['UNSIGNED'] = FALSE;
  737. if (is_array($this->_unsigned))
  738. {
  739. foreach (array_keys($this->_unsigned) as $key)
  740. {
  741. if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
  742. {
  743. $field['unsigned'] = ' UNSIGNED';
  744. return;
  745. }
  746. elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
  747. {
  748. $field['type'] = $key;
  749. return;
  750. }
  751. }
  752. return;
  753. }
  754. $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
  755. }
  756. // --------------------------------------------------------------------
  757. /**
  758. * Field attribute DEFAULT
  759. *
  760. * @param array &$attributes
  761. * @param array &$field
  762. * @return void
  763. */
  764. protected function _attr_default(&$attributes, &$field)
  765. {
  766. if ($this->_default === FALSE)
  767. {
  768. return;
  769. }
  770. if (array_key_exists('DEFAULT', $attributes))
  771. {
  772. if ($attributes['DEFAULT'] === NULL)
  773. {
  774. $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
  775. // Override the NULL attribute if that's our default
  776. $attributes['NULL'] = TRUE;
  777. $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
  778. }
  779. else
  780. {
  781. $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
  782. }
  783. }
  784. }
  785. // --------------------------------------------------------------------
  786. /**
  787. * Field attribute UNIQUE
  788. *
  789. * @param array &$attributes
  790. * @param array &$field
  791. * @return void
  792. */
  793. protected function _attr_unique(&$attributes, &$field)
  794. {
  795. if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
  796. {
  797. $field['unique'] = ' UNIQUE';
  798. }
  799. }
  800. // --------------------------------------------------------------------
  801. /**
  802. * Field attribute AUTO_INCREMENT
  803. *
  804. * @param array &$attributes
  805. * @param array &$field
  806. * @return void
  807. */
  808. protected function _attr_auto_increment(&$attributes, &$field)
  809. {
  810. if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
  811. {
  812. $field['auto_increment'] = ' AUTO_INCREMENT';
  813. }
  814. }
  815. // --------------------------------------------------------------------
  816. /**
  817. * Process primary keys
  818. *
  819. * @param string $table Table name
  820. * @return string
  821. */
  822. protected function _process_primary_keys($table)
  823. {
  824. $sql = '';
  825. for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
  826. {
  827. if ( ! isset($this->fields[$this->primary_keys[$i]]))
  828. {
  829. unset($this->primary_keys[$i]);
  830. }
  831. }
  832. if (count($this->primary_keys) > 0)
  833. {
  834. $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
  835. .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
  836. }
  837. return $sql;
  838. }
  839. // --------------------------------------------------------------------
  840. /**
  841. * Process indexes
  842. *
  843. * @param string $table Table name
  844. * @return string[] list of SQL statements
  845. */
  846. protected function _process_indexes($table)
  847. {
  848. $sqls = array();
  849. for ($i = 0, $c = count($this->keys); $i < $c; $i++)
  850. {
  851. if (is_array($this->keys[$i]))
  852. {
  853. for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
  854. {
  855. if ( ! isset($this->fields[$this->keys[$i][$i2]]))
  856. {
  857. unset($this->keys[$i][$i2]);
  858. continue;
  859. }
  860. }
  861. }
  862. elseif ( ! isset($this->fields[$this->keys[$i]]))
  863. {
  864. unset($this->keys[$i]);
  865. continue;
  866. }
  867. is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
  868. $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
  869. .' ON '.$this->db->escape_identifiers($table)
  870. .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
  871. }
  872. return $sqls;
  873. }
  874. // --------------------------------------------------------------------
  875. /**
  876. * Reset
  877. *
  878. * Resets table creation vars
  879. *
  880. * @return void
  881. */
  882. protected function _reset()
  883. {
  884. $this->fields = $this->keys = $this->primary_keys = array();
  885. }
  886. }