Subversion-Projekte lars-tiefland.ci

Revision

Revision 2254 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
68 lars 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
 *
2257 lars 9
 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
68 lars 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/)
2257 lars 32
 * @copyright	Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
68 lars 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
/**
41
 * Database Forge Class
42
 *
43
 * @category	Database
44
 * @author		EllisLab Dev Team
45
 * @link		https://codeigniter.com/user_guide/database/
46
 */
47
abstract class CI_DB_forge {
48
 
49
	/**
50
	 * Database object
51
	 *
52
	 * @var	object
53
	 */
54
	protected $db;
55
 
56
	/**
57
	 * Fields data
58
	 *
59
	 * @var	array
60
	 */
61
	public $fields		= array();
62
 
63
	/**
64
	 * Keys data
65
	 *
66
	 * @var	array
67
	 */
68
	public $keys		= array();
69
 
70
	/**
71
	 * Primary Keys data
72
	 *
73
	 * @var	array
74
	 */
75
	public $primary_keys	= array();
76
 
77
	/**
78
	 * Database character set
79
	 *
80
	 * @var	string
81
	 */
82
	public $db_char_set	= '';
83
 
84
	// --------------------------------------------------------------------
85
 
86
	/**
87
	 * CREATE DATABASE statement
88
	 *
89
	 * @var	string
90
	 */
91
	protected $_create_database	= 'CREATE DATABASE %s';
92
 
93
	/**
94
	 * DROP DATABASE statement
95
	 *
96
	 * @var	string
97
	 */
98
	protected $_drop_database	= 'DROP DATABASE %s';
99
 
100
	/**
101
	 * CREATE TABLE statement
102
	 *
103
	 * @var	string
104
	 */
105
	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';
130
 
131
	/**
132
	 * RENAME TABLE statement
133
	 *
134
	 * @var	string
135
	 */
136
	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 representation 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 ';
158
 
159
	// --------------------------------------------------------------------
160
 
161
	/**
162
	 * Class constructor
163
	 *
164
	 * @param	object	&$db	Database object
165
	 * @return	void
166
	 */
167
	public function __construct(&$db)
168
	{
169
		$this->db =& $db;
170
		log_message('info', 'Database Forge Class Initialized');
171
	}
172
 
173
	// --------------------------------------------------------------------
174
 
175
	/**
176
	 * Create database
177
	 *
178
	 * @param	string	$db_name
179
	 * @return	bool
180
	 */
181
	public function create_database($db_name)
182
	{
183
		if ($this->_create_database === FALSE)
184
		{
185
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
186
		}
1257 lars 187
		elseif ( ! $this->db->query(sprintf($this->_create_database, $this->db->escape_identifiers($db_name), $this->db->char_set, $this->db->dbcollat)))
68 lars 188
		{
189
			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
190
		}
191
 
192
		if ( ! empty($this->db->data_cache['db_names']))
193
		{
194
			$this->db->data_cache['db_names'][] = $db_name;
195
		}
196
 
197
		return TRUE;
198
	}
199
 
200
	// --------------------------------------------------------------------
201
 
202
	/**
203
	 * Drop database
204
	 *
205
	 * @param	string	$db_name
206
	 * @return	bool
207
	 */
208
	public function drop_database($db_name)
209
	{
210
		if ($this->_drop_database === FALSE)
211
		{
212
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
213
		}
1257 lars 214
		elseif ( ! $this->db->query(sprintf($this->_drop_database, $this->db->escape_identifiers($db_name))))
68 lars 215
		{
216
			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
217
		}
218
 
219
		if ( ! empty($this->db->data_cache['db_names']))
220
		{
221
			$key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
222
			if ($key !== FALSE)
223
			{
224
				unset($this->db->data_cache['db_names'][$key]);
225
			}
226
		}
227
 
228
		return TRUE;
229
	}
230
 
231
	// --------------------------------------------------------------------
232
 
233
	/**
234
	 * Add Key
235
	 *
236
	 * @param	string	$key
237
	 * @param	bool	$primary
238
	 * @return	CI_DB_forge
239
	 */
240
	public function add_key($key, $primary = FALSE)
241
	{
242
		// DO NOT change this! This condition is only applicable
243
		// for PRIMARY keys because you can only have one such,
244
		// and therefore all fields you add to it will be included
245
		// in the same, composite PRIMARY KEY.
246
		//
247
		// It's not the same for regular indexes.
248
		if ($primary === TRUE && is_array($key))
249
		{
250
			foreach ($key as $one)
251
			{
252
				$this->add_key($one, $primary);
253
			}
254
 
255
			return $this;
256
		}
257
 
258
		if ($primary === TRUE)
259
		{
260
			$this->primary_keys[] = $key;
261
		}
262
		else
263
		{
264
			$this->keys[] = $key;
265
		}
266
 
267
		return $this;
268
	}
269
 
270
	// --------------------------------------------------------------------
271
 
272
	/**
273
	 * Add Field
274
	 *
275
	 * @param	array	$field
276
	 * @return	CI_DB_forge
277
	 */
278
	public function add_field($field)
279
	{
280
		if (is_string($field))
281
		{
282
			if ($field === 'id')
283
			{
284
				$this->add_field(array(
285
					'id' => array(
286
						'type' => 'INT',
287
						'constraint' => 9,
288
						'auto_increment' => TRUE
289
					)
290
				));
291
				$this->add_key('id', TRUE);
292
			}
293
			else
294
			{
295
				if (strpos($field, ' ') === FALSE)
296
				{
297
					show_error('Field information is required for that operation.');
298
				}
299
 
300
				$this->fields[] = $field;
301
			}
302
		}
303
 
304
		if (is_array($field))
305
		{
306
			$this->fields = array_merge($this->fields, $field);
307
		}
308
 
309
		return $this;
310
	}
311
 
312
	// --------------------------------------------------------------------
313
 
314
	/**
315
	 * Create Table
316
	 *
317
	 * @param	string	$table		Table name
318
	 * @param	bool	$if_not_exists	Whether to add IF NOT EXISTS condition
319
	 * @param	array	$attributes	Associative array of table attributes
320
	 * @return	bool
321
	 */
322
	public function create_table($table, $if_not_exists = FALSE, array $attributes = array())
323
	{
324
		if ($table === '')
325
		{
326
			show_error('A table name is required for that operation.');
327
		}
328
		else
329
		{
330
			$table = $this->db->dbprefix.$table;
331
		}
332
 
333
		if (count($this->fields) === 0)
334
		{
335
			show_error('Field information is required.');
336
		}
337
 
338
		$sql = $this->_create_table($table, $if_not_exists, $attributes);
339
 
340
		if (is_bool($sql))
341
		{
342
			$this->_reset();
343
			if ($sql === FALSE)
344
			{
345
				return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
346
			}
347
		}
348
 
349
		if (($result = $this->db->query($sql)) !== FALSE)
350
		{
2049 lars 351
			isset($this->db->data_cache['table_names']) && $this->db->data_cache['table_names'][] = $table;
68 lars 352
 
353
			// Most databases don't support creating indexes from within the CREATE TABLE statement
354
			if ( ! empty($this->keys))
355
			{
356
				for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
357
				{
358
					$this->db->query($sqls[$i]);
359
				}
360
			}
361
		}
362
 
363
		$this->_reset();
364
		return $result;
365
	}
366
 
367
	// --------------------------------------------------------------------
368
 
369
	/**
370
	 * Create Table
371
	 *
372
	 * @param	string	$table		Table name
373
	 * @param	bool	$if_not_exists	Whether to add 'IF NOT EXISTS' condition
374
	 * @param	array	$attributes	Associative array of table attributes
375
	 * @return	mixed
376
	 */
377
	protected function _create_table($table, $if_not_exists, $attributes)
378
	{
379
		if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
380
		{
381
			if ($this->db->table_exists($table))
382
			{
383
				return TRUE;
384
			}
2257 lars 385
 
386
			$if_not_exists = FALSE;
68 lars 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
		{
407
			$columns .= $this->_process_indexes($table);
408
		}
409
 
410
		// _create_table will usually have the following format: "%s %s (%s\n)"
411
		$sql = sprintf($this->_create_table.'%s',
412
			$sql,
413
			$this->db->escape_identifiers($table),
414
			$columns,
415
			$this->_create_table_attr($attributes)
416
		);
417
 
418
		return $sql;
419
	}
420
 
421
	// --------------------------------------------------------------------
422
 
423
	/**
424
	 * 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
	/**
447
	 * Drop Table
448
	 *
449
	 * @param	string	$table_name	Table name
450
	 * @param	bool	$if_exists	Whether to add an IF EXISTS condition
451
	 * @return	bool
452
	 */
453
	public function drop_table($table_name, $if_exists = FALSE)
454
	{
455
		if ($table_name === '')
456
		{
457
			return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
458
		}
459
 
460
		if (($query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists)) === TRUE)
461
		{
462
			return TRUE;
463
		}
464
 
465
		$query = $this->db->query($query);
466
 
467
		// Update table list cache
468
		if ($query && ! empty($this->db->data_cache['table_names']))
469
		{
470
			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
471
			if ($key !== FALSE)
472
			{
473
				unset($this->db->data_cache['table_names'][$key]);
474
			}
475
		}
476
 
477
		return $query;
478
	}
479
 
480
	// --------------------------------------------------------------------
481
 
482
	/**
483
	 * Drop Table
484
	 *
485
	 * Generates a platform-specific DROP TABLE string
486
	 *
487
	 * @param	string	$table		Table name
488
	 * @param	bool	$if_exists	Whether to add an IF EXISTS condition
2107 lars 489
	 * @return	mixed	(Returns a platform-specific DROP table string, or TRUE to indicate there's nothing to do)
68 lars 490
	 */
491
	protected function _drop_table($table, $if_exists)
492
	{
493
		$sql = 'DROP TABLE';
494
 
495
		if ($if_exists)
496
		{
497
			if ($this->_drop_table_if === FALSE)
498
			{
499
				if ( ! $this->db->table_exists($table))
500
				{
501
					return TRUE;
502
				}
503
			}
504
			else
505
			{
506
				$sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
507
			}
508
		}
509
 
510
		return $sql.' '.$this->db->escape_identifiers($table);
511
	}
512
 
513
	// --------------------------------------------------------------------
514
 
515
	/**
516
	 * Rename Table
517
	 *
518
	 * @param	string	$table_name	Old table name
519
	 * @param	string	$new_table_name	New table name
520
	 * @return	bool
521
	 */
522
	public function rename_table($table_name, $new_table_name)
523
	{
524
		if ($table_name === '' OR $new_table_name === '')
525
		{
526
			show_error('A table name is required for that operation.');
527
			return FALSE;
528
		}
529
		elseif ($this->_rename_table === FALSE)
530
		{
531
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
532
		}
533
 
534
		$result = $this->db->query(sprintf($this->_rename_table,
535
						$this->db->escape_identifiers($this->db->dbprefix.$table_name),
536
						$this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
537
					);
538
 
539
		if ($result && ! empty($this->db->data_cache['table_names']))
540
		{
541
			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
542
			if ($key !== FALSE)
543
			{
544
				$this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
545
			}
546
		}
547
 
548
		return $result;
549
	}
550
 
551
	// --------------------------------------------------------------------
552
 
553
	/**
554
	 * Column Add
555
	 *
556
	 * @todo	Remove deprecated $_after option in 3.1+
557
	 * @param	string	$table	Table name
558
	 * @param	array	$field	Column definition
559
	 * @param	string	$_after	Column for AFTER clause (deprecated)
560
	 * @return	bool
561
	 */
562
	public function add_column($table, $field, $_after = NULL)
563
	{
564
		// Work-around for literal column definitions
565
		is_array($field) OR $field = array($field);
566
 
567
		foreach (array_keys($field) as $k)
568
		{
569
			// Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
570
			if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
571
			{
572
				$field[$k]['after'] = $_after;
573
			}
574
 
575
			$this->add_field(array($k => $field[$k]));
576
		}
577
 
578
		$sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
579
		$this->_reset();
580
		if ($sqls === FALSE)
581
		{
582
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
583
		}
584
 
585
		for ($i = 0, $c = count($sqls); $i < $c; $i++)
586
		{
587
			if ($this->db->query($sqls[$i]) === FALSE)
588
			{
589
				return FALSE;
590
			}
591
		}
592
 
593
		return TRUE;
594
	}
595
 
596
	// --------------------------------------------------------------------
597
 
598
	/**
599
	 * Column Drop
600
	 *
601
	 * @param	string	$table		Table name
602
	 * @param	string	$column_name	Column name
603
	 * @return	bool
604
	 */
605
	public function drop_column($table, $column_name)
606
	{
607
		$sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
608
		if ($sql === FALSE)
609
		{
610
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
611
		}
612
 
613
		return $this->db->query($sql);
614
	}
615
 
616
	// --------------------------------------------------------------------
617
 
618
	/**
619
	 * Column Modify
620
	 *
621
	 * @param	string	$table	Table name
622
	 * @param	string	$field	Column definition
623
	 * @return	bool
624
	 */
625
	public function modify_column($table, $field)
626
	{
627
		// Work-around for literal column definitions
628
		is_array($field) OR $field = array($field);
629
 
630
		foreach (array_keys($field) as $k)
631
		{
632
			$this->add_field(array($k => $field[$k]));
633
		}
634
 
635
		if (count($this->fields) === 0)
636
		{
637
			show_error('Field information is required.');
638
		}
639
 
640
		$sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
641
		$this->_reset();
642
		if ($sqls === FALSE)
643
		{
644
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
645
		}
646
 
647
		for ($i = 0, $c = count($sqls); $i < $c; $i++)
648
		{
649
			if ($this->db->query($sqls[$i]) === FALSE)
650
			{
651
				return FALSE;
652
			}
653
		}
654
 
655
		return TRUE;
656
	}
657
 
658
	// --------------------------------------------------------------------
659
 
660
	/**
661
	 * ALTER TABLE
662
	 *
663
	 * @param	string	$alter_type	ALTER type
664
	 * @param	string	$table		Table name
665
	 * @param	mixed	$field		Column definition
666
	 * @return	string|string[]
667
	 */
668
	protected function _alter_table($alter_type, $table, $field)
669
	{
670
		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
671
 
672
		// DROP has everything it needs now.
673
		if ($alter_type === 'DROP')
674
		{
675
			return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
676
		}
677
 
678
		$sql .= ($alter_type === 'ADD')
679
			? 'ADD '
680
			: $alter_type.' COLUMN ';
681
 
682
		$sqls = array();
683
		for ($i = 0, $c = count($field); $i < $c; $i++)
684
		{
685
			$sqls[] = $sql
686
				.($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
687
		}
688
 
689
		return $sqls;
690
	}
691
 
692
	// --------------------------------------------------------------------
693
 
694
	/**
695
	 * Process fields
696
	 *
697
	 * @param	bool	$create_table
698
	 * @return	array
699
	 */
700
	protected function _process_fields($create_table = FALSE)
701
	{
702
		$fields = array();
703
 
704
		foreach ($this->fields as $key => $attributes)
705
		{
706
			if (is_int($key) && ! is_array($attributes))
707
			{
708
				$fields[] = array('_literal' => $attributes);
709
				continue;
710
			}
711
 
712
			$attributes = array_change_key_case($attributes, CASE_UPPER);
713
 
714
			if ($create_table === TRUE && empty($attributes['TYPE']))
715
			{
716
				continue;
717
			}
718
 
719
			isset($attributes['TYPE']) && $this->_attr_type($attributes);
720
 
721
			$field = array(
722
				'name'			=> $key,
723
				'new_name'		=> isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
724
				'type'			=> isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
725
				'length'		=> '',
726
				'unsigned'		=> '',
727
				'null'			=> '',
728
				'unique'		=> '',
729
				'default'		=> '',
730
				'auto_increment'	=> '',
731
				'_literal'		=> FALSE
732
			);
733
 
734
			isset($attributes['TYPE']) && $this->_attr_unsigned($attributes, $field);
735
 
736
			if ($create_table === FALSE)
737
			{
738
				if (isset($attributes['AFTER']))
739
				{
740
					$field['after'] = $attributes['AFTER'];
741
				}
742
				elseif (isset($attributes['FIRST']))
743
				{
744
					$field['first'] = (bool) $attributes['FIRST'];
745
				}
746
			}
747
 
748
			$this->_attr_default($attributes, $field);
749
 
750
			if (isset($attributes['NULL']))
751
			{
752
				if ($attributes['NULL'] === TRUE)
753
				{
754
					$field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
755
				}
756
				else
757
				{
758
					$field['null'] = ' NOT NULL';
759
				}
760
			}
761
			elseif ($create_table === TRUE)
762
			{
763
				$field['null'] = ' NOT NULL';
764
			}
765
 
766
			$this->_attr_auto_increment($attributes, $field);
767
			$this->_attr_unique($attributes, $field);
768
 
769
			if (isset($attributes['COMMENT']))
770
			{
771
				$field['comment'] = $this->db->escape($attributes['COMMENT']);
772
			}
773
 
774
			if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
775
			{
776
				switch (strtoupper($attributes['TYPE']))
777
				{
778
					case 'ENUM':
779
					case 'SET':
780
						$attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
781
					default:
782
						$field['length'] = is_array($attributes['CONSTRAINT'])
783
							? '('.implode(',', $attributes['CONSTRAINT']).')'
784
							: '('.$attributes['CONSTRAINT'].')';
785
						break;
786
				}
787
			}
788
 
789
			$fields[] = $field;
790
		}
791
 
792
		return $fields;
793
	}
794
 
795
	// --------------------------------------------------------------------
796
 
797
	/**
798
	 * Process column
799
	 *
800
	 * @param	array	$field
801
	 * @return	string
802
	 */
803
	protected function _process_column($field)
804
	{
805
		return $this->db->escape_identifiers($field['name'])
806
			.' '.$field['type'].$field['length']
807
			.$field['unsigned']
808
			.$field['default']
809
			.$field['null']
810
			.$field['auto_increment']
811
			.$field['unique'];
812
	}
813
 
814
	// --------------------------------------------------------------------
815
 
816
	/**
817
	 * Field attribute TYPE
818
	 *
819
	 * Performs a data type mapping between different databases.
820
	 *
821
	 * @param	array	&$attributes
822
	 * @return	void
823
	 */
824
	protected function _attr_type(&$attributes)
825
	{
826
		// Usually overridden by drivers
827
	}
828
 
829
	// --------------------------------------------------------------------
830
 
831
	/**
832
	 * Field attribute UNSIGNED
833
	 *
834
	 * Depending on the _unsigned property value:
835
	 *
836
	 *	- TRUE will always set $field['unsigned'] to 'UNSIGNED'
837
	 *	- FALSE will always set $field['unsigned'] to ''
838
	 *	- array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
839
	 *		if $attributes['TYPE'] is found in the array
840
	 *	- array(TYPE => UTYPE) will change $field['type'],
841
	 *		from TYPE to UTYPE in case of a match
842
	 *
843
	 * @param	array	&$attributes
844
	 * @param	array	&$field
845
	 * @return	void
846
	 */
847
	protected function _attr_unsigned(&$attributes, &$field)
848
	{
849
		if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
850
		{
851
			return;
852
		}
853
 
854
		// Reset the attribute in order to avoid issues if we do type conversion
855
		$attributes['UNSIGNED'] = FALSE;
856
 
857
		if (is_array($this->_unsigned))
858
		{
859
			foreach (array_keys($this->_unsigned) as $key)
860
			{
861
				if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
862
				{
863
					$field['unsigned'] = ' UNSIGNED';
864
					return;
865
				}
866
				elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
867
				{
868
					$field['type'] = $key;
869
					return;
870
				}
871
			}
872
 
873
			return;
874
		}
875
 
876
		$field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
877
	}
878
 
879
	// --------------------------------------------------------------------
880
 
881
	/**
882
	 * Field attribute DEFAULT
883
	 *
884
	 * @param	array	&$attributes
885
	 * @param	array	&$field
886
	 * @return	void
887
	 */
888
	protected function _attr_default(&$attributes, &$field)
889
	{
890
		if ($this->_default === FALSE)
891
		{
892
			return;
893
		}
894
 
895
		if (array_key_exists('DEFAULT', $attributes))
896
		{
897
			if ($attributes['DEFAULT'] === NULL)
898
			{
899
				$field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
900
 
901
				// Override the NULL attribute if that's our default
902
				$attributes['NULL'] = TRUE;
903
				$field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
904
			}
905
			else
906
			{
907
				$field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
908
			}
909
		}
910
	}
911
 
912
	// --------------------------------------------------------------------
913
 
914
	/**
915
	 * Field attribute UNIQUE
916
	 *
917
	 * @param	array	&$attributes
918
	 * @param	array	&$field
919
	 * @return	void
920
	 */
921
	protected function _attr_unique(&$attributes, &$field)
922
	{
923
		if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
924
		{
925
			$field['unique'] = ' UNIQUE';
926
		}
927
	}
928
 
929
	// --------------------------------------------------------------------
930
 
931
	/**
932
	 * Field attribute AUTO_INCREMENT
933
	 *
934
	 * @param	array	&$attributes
935
	 * @param	array	&$field
936
	 * @return	void
937
	 */
938
	protected function _attr_auto_increment(&$attributes, &$field)
939
	{
940
		if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
941
		{
942
			$field['auto_increment'] = ' AUTO_INCREMENT';
943
		}
944
	}
945
 
946
	// --------------------------------------------------------------------
947
 
948
	/**
949
	 * Process primary keys
950
	 *
951
	 * @param	string	$table	Table name
952
	 * @return	string
953
	 */
954
	protected function _process_primary_keys($table)
955
	{
956
		$sql = '';
957
 
958
		for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
959
		{
960
			if ( ! isset($this->fields[$this->primary_keys[$i]]))
961
			{
962
				unset($this->primary_keys[$i]);
963
			}
964
		}
965
 
966
		if (count($this->primary_keys) > 0)
967
		{
968
			$sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
969
				.' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
970
		}
971
 
972
		return $sql;
973
	}
974
 
975
	// --------------------------------------------------------------------
976
 
977
	/**
978
	 * Process indexes
979
	 *
2107 lars 980
	 * @param	string	$table	Table name
981
	 * @return	string[] list of SQL statements
68 lars 982
	 */
983
	protected function _process_indexes($table)
984
	{
985
		$sqls = array();
986
 
987
		for ($i = 0, $c = count($this->keys); $i < $c; $i++)
988
		{
989
			if (is_array($this->keys[$i]))
990
			{
991
				for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
992
				{
993
					if ( ! isset($this->fields[$this->keys[$i][$i2]]))
994
					{
995
						unset($this->keys[$i][$i2]);
996
						continue;
997
					}
998
				}
999
			}
1000
			elseif ( ! isset($this->fields[$this->keys[$i]]))
1001
			{
1002
				unset($this->keys[$i]);
1003
				continue;
1004
			}
1005
 
1006
			is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
1007
 
1008
			$sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
1009
				.' ON '.$this->db->escape_identifiers($table)
1010
				.' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
1011
		}
1012
 
1013
		return $sqls;
1014
	}
1015
 
1016
	// --------------------------------------------------------------------
1017
 
1018
	/**
1019
	 * Reset
1020
	 *
1021
	 * Resets table creation vars
1022
	 *
1023
	 * @return	void
1024
	 */
1025
	protected function _reset()
1026
	{
1027
		$this->fields = $this->keys = $this->primary_keys = array();
1028
	}
1029
 
1030
}