Completed
Push — master ( 5e6958...9a3621 )
by Richard
11s
created

Tables::truncate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 11
loc 11
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
namespace Xmf\Database;
13
14
use Xmf\Language;
15
16
/**
17
 * Xmf\Database\Tables
18
 *
19
 * inspired by Yii CDbMigration
20
 *
21
 * Build a work queue of database changes needed to implement new and
22
 * changed tables. Define table(s) you are dealing with and any desired
23
 * change(s). If the changes are already in place (i.e. the new column
24
 * already exists) no work is added. Then executeQueue() to process the
25
 * whole set.
26
 *
27
 * @category  Xmf\Database\Tables
28
 * @package   Xmf
29
 * @author    Richard Griffith <[email protected]>
30
 * @copyright 2011-2016 XOOPS Project (http://xoops.org)
31
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
32
 * @version   Release: 1.0
33
 * @link      http://xoops.org
34
 * @since     1.0
35
 */
36
class Tables
37
{
38
    /**
39
     * @var \XoopsDatabase
40
     */
41
    protected $db;
42
43
    /**
44
     * @var string
45
     */
46
    protected $databaseName;
47
48
    /**
49
     * @var array Tables
50
     */
51
    protected $tables;
52
53
    /**
54
     * @var array Work queue
55
     */
56
    protected $queue;
57
58
    /**
59
     * @var string last error message
60
     */
61
    protected $lastError;
62
63
    /**
64
     * @var int last error number
65
     */
66
    protected $lastErrNo;
67
68
    /**
69
     * Constructor
70
     *
71
     */
72
    public function __construct()
73
    {
74
        Language::load('xmf');
75
76
        $this->db = \XoopsDatabaseFactory::getDatabaseConnection();
77
        $this->databaseName = XOOPS_DB_NAME;
78
        $this->resetQueue();
79
    }
80
81
    /**
82
     * Return a table name, prefixed with site table prefix
83
     *
84
     * @param string $table table name to contain prefix
85
     *
86
     * @return string table name with prefix
87
     */
88
    protected function name($table)
89
    {
90
        return $this->db->prefix($table);
91
    }
92
93
    /**
94
     * Add new column for table to the work queue
95
     *
96
     * @param string $table      table to contain the column
97
     * @param string $column     name of column to add
98
     * @param string $attributes column_definition
99
     *
100
     * @return bool true if no errors, false if errors encountered
101
     */
102
    public function addColumn($table, $column, $attributes)
103
    {
104
        $columnDef = array(
105
            'name' => $column,
106
            'attributes' => $attributes
107
        );
108
109
        // Find table def.
110
        if (isset($this->tables[$table])) {
111
            $tableDef = &$this->tables[$table];
112
            // Is this on a table we are adding?
113
            if (isset($tableDef['create']) && $tableDef['create']) {
114
                array_push($tableDef['columns'], $columnDef);
115
            } else {
116 View Code Duplication
                foreach ($tableDef['columns'] as $col) {
117
                    if (strcasecmp($col['name'], $column) == 0) {
118
                        return true;
119
                    }
120
                }
121
                $this->queue[] = "ALTER TABLE `{$tableDef['name']}`"
122
                    . " ADD COLUMN `{$column}` {$columnDef['attributes']}";
123
            }
124
        } else {
125
            return $this->tableNotEstablished();
126
        }
127
128
        return true; // exists or is added to queue
129
    }
130
131
    /**
132
     * Add new primary key definition for table to work queue
133
     *
134
     * @param string $table  table
135
     * @param string $column column or comma separated list of columns
136
     *                       to use as primary key
137
     *
138
     * @return bool true if no errors, false if errors encountered
139
     */
140
    public function addPrimaryKey($table, $column)
141
    {
142
        $columns = str_getcsv(str_replace(' ', '', $column));
143
        $columnList = '';
144
        $firstComma = '';
145
        foreach ($columns as $col) {
146
            $columnList .= "{$firstComma}`{$col}`";
147
            $firstComma = ', ';
148
        }
149
        if (isset($this->tables[$table])) {
150
            if (isset($this->tables[$table]['create']) && $this->tables[$table]['create']) {
151
                $this->tables[$table]['keys']['PRIMARY']['columns'] = $columnList;
152
            } else {
153
                $this->queue[] = "ALTER TABLE `{$this->tables[$table]['name']}` ADD PRIMARY KEY({$columnList})";
154
            }
155
        } else {
156
            return $this->tableNotEstablished();
157
        }
158
159
        return true;
160
    }
161
162
    /**
163
     * Add new index definition for index to work queue
164
     *
165
     * @param string $name   name of index to add
166
     * @param string $table  table indexed
167
     * @param string $column column or a comma separated list of columns
168
     *                        to use as the key
169
     * @param bool   $unique true if index is to be unique
170
     *
171
     * @return bool true if no errors, false if errors encountered
172
     */
173
    public function addIndex($name, $table, $column, $unique = false)
174
    {
175
        $columns = str_getcsv(str_replace(' ', '', $column));
176
        $columnList = '';
177
        $firstComma = '';
178
        foreach ($columns as $col) {
179
            $columnList .= "{$firstComma}`{$col}`";
180
            $firstComma = ', ';
181
        }
182
        if (isset($this->tables[$table])) {
183
            if (isset($this->tables[$table]['create']) && $this->tables[$table]['create']) {
184
                $this->tables[$table]['keys'][$name]['columns'] = $columnList;
185
                $this->tables[$table]['keys'][$name]['unique'] = (bool) $unique;
186
            } else {
187
                $add = ($unique ? 'ADD UNIQUE INDEX' : 'ADD INDEX');
188
                $this->queue[] = "ALTER TABLE `{$this->tables[$table]['name']}` {$add} `{$name}` ({$columnList})";
189
            }
190
        } else {
191
            return $this->tableNotEstablished();
192
        }
193
194
        return true;
195
    }
196
197
    /**
198
     * Load table schema from database, or starts new empty schema if
199
     * table does not exist
200
     *
201
     * @param string $table table
202
     *
203
     * @return bool true if no errors, false if errors encountered
204
     */
205
    public function addTable($table)
206
    {
207
        if (isset($this->tables[$table])) {
208
            return true;
209
        }
210
        $tableDef = $this->getTable($table);
211
        if (is_array($tableDef)) {
212
            $this->tables[$table] = $tableDef;
213
214
            return true;
215
        } else {
216
            if ($tableDef === true) {
217
                $tableDef = array(
218
                    'name' => $this->name($table),
219
                    'options' => 'ENGINE=InnoDB',
220
                    'columns' => array(),
221
                    'keys' => array(),
222
                    'create' => true,
223
                );
224
                $this->tables[$table] = $tableDef;
225
226
                $this->queue[] = array('createtable' => $table);
227
228
                return true;
229
            } else {
230
                return false;
231
            }
232
        }
233
    }
234
235
    /**
236
     * AddTable only if it exists
237
     *
238
     * @param string $table table
239
     *
240
     * @return bool true if table exists, false otherwise
241
     */
242
    public function useTable($table)
243
    {
244
        if (isset($this->tables[$table])) {
245
            return true;
246
        }
247
        $tableDef = $this->getTable($table);
248
        if (is_array($tableDef)) {
249
            $this->tables[$table] = $tableDef;
250
            return true;
251
        }
252
        return false;
253
    }
254
255
    /**
256
     * Get column attributes
257
     *
258
     * @param string $table  table containing the column
259
     * @param string $column column to alter
260
     *
261
     * @return string|bool attribute string, or false if error encountered
262
     */
263
    public function getColumnAttributes($table, $column)
264
    {
265
        // Find table def.
266
        if (isset($this->tables[$table])) {
267
            $tableDef = $this->tables[$table];
268
            // loop thru and find the column
269 View Code Duplication
            foreach ($tableDef['columns'] as $col) {
270
                if (strcasecmp($col['name'], $column) === 0) {
271
                    return $col['attributes'];
272
                }
273
            }
274
        }
275
276
        return false;
277
    }
278
279
    /**
280
     * Get indexes for a table
281
     *
282
     * @param string $table get indexes for this named table
283
     *
284
     * @return array|bool array of indexes, or false if error encountered
285
     */
286
    public function getTableIndexes($table)
287
    {
288
        // Find table def.
289
        if (isset($this->tables[$table]) && isset($this->tables[$table]['keys'])) {
290
            return $this->tables[$table]['keys'];
291
        }
292
293
        return false;
294
    }
295
296
    /**
297
     * Add alter column operation to the work queue
298
     *
299
     * @param string $table      table containing the column
300
     * @param string $column     column to alter
301
     * @param string $attributes new column_definition
302
     * @param string $newName    new name for column, blank to keep same
303
     *
304
     * @return bool true if no errors, false if errors encountered
305
     */
306
    public function alterColumn($table, $column, $attributes, $newName = '')
307
    {
308
        if (empty($newName)) {
309
            $newName = $column;
310
        }
311
        // Find table def.
312
        if (isset($this->tables[$table])) {
313
            $tableDef = &$this->tables[$table];
314
            // Is this on a table we are adding?
315
            if (isset($tableDef['create']) && $tableDef['create']) {
316
                // loop thru and find the column
317
                foreach ($tableDef['columns'] as &$col) {
318
                    if (strcasecmp($col['name'], $column) == 0) {
319
                        $col['name'] = $newName;
320
                        $col['attributes'] = $attributes;
321
                        break;
322
                    }
323
                }
324
325
                return true;
326
            } else {
327
                $this->queue[] = "ALTER TABLE `{$tableDef['name']}` " .
328
                    "CHANGE COLUMN `{$column}` `{$newName}` {$attributes} ";
329
            }
330
        } else {
331
            return $this->tableNotEstablished();
332
        }
333
334
        return true;
335
    }
336
337
    /**
338
     * Loads table schema from database, and adds newTable with that
339
     * schema to the queue
340
     *
341
     * @param string $table    existing table
342
     * @param string $newTable new table
343
     * @param bool   $withData true to copy data, false for schema only
344
     *
345
     * @return bool true if no errors, false if errors encountered
346
     */
347
    public function copyTable($table, $newTable, $withData = false)
348
    {
349
        if (isset($this->tables[$newTable])) {
350
            return true;
351
        }
352
        $tableDef = $this->getTable($table);
353
        $copy = $this->name($newTable);
354
        $original = $this->name($table);
355
356
        if (is_array($tableDef)) {
357
            $tableDef['name'] = $copy;
358
            if ($withData) {
359
                $this->queue[] = "CREATE TABLE `{$copy}` LIKE `{$original}` ;";
360
                $this->queue[] = "INSERT INTO `{$copy}` SELECT * FROM `{$original}` ;";
361
            } else {
362
                $tableDef['create'] = true;
363
                $this->queue[] = array('createtable' => $newTable);
364
            }
365
            $this->tables[$newTable] = $tableDef;
366
367
            return true;
368
        } else {
369
            return false;
370
        }
371
    }
372
373
    /**
374
     * Add drop column operation to the work queue
375
     *
376
     * @param string $table  table containing the column
377
     * @param string $column column to drop
378
     *
379
     * @return bool true if no errors, false if errors encountered
380
     */
381 View Code Duplication
    public function dropColumn($table, $column)
382
    {
383
        // Find table def.
384
        if (isset($this->tables[$table])) {
385
            $tableDef = $this->tables[$table];
386
            $this->queue[] = "ALTER TABLE `{$tableDef['name']}` DROP COLUMN `{$column}`";
387
        } else {
388
            return $this->tableNotEstablished();
389
        }
390
391
        return true;
392
    }
393
394
    /**
395
     * Add drop index operation to the work queue
396
     *
397
     * @param string $name  name of index to drop
398
     * @param string $table table indexed
399
     *
400
     * @return bool true if no errors, false if errors encountered
401
     */
402 View Code Duplication
    public function dropIndex($name, $table)
403
    {
404
        if (isset($this->tables[$table])) {
405
            $tableDef = $this->tables[$table];
406
            $this->queue[] = "ALTER TABLE `{$tableDef['name']}` DROP INDEX `{$name}`";
407
        } else {
408
            return $this->tableNotEstablished();
409
        }
410
411
        return true;
412
    }
413
414
    /**
415
     * Add drop for all (non-PRIMARY) keys for a table to the work
416
     * queue. This can be used to clean up indexes with automatic names.
417
     *
418
     * @param string $table table indexed
419
     *
420
     * @return bool true if no errors, false if errors encountered
421
     */
422
    public function dropIndexes($table)
423
    {
424
        // Find table def.
425
        if (isset($this->tables[$table])) {
426
            $tableDef = &$this->tables[$table];
427
            // Is this on a table we are adding?
428
            if (isset($tableDef['create']) && $tableDef['create']) {
429
                // strip everything but the PRIMARY from definition
430 View Code Duplication
                foreach ($tableDef['keys'] as $keyName => $key) {
431
                    if ($keyName !== 'PRIMARY') {
432
                        unset($tableDef['keys'][$keyName]);
433
                    }
434
                }
435
            } else {
436
                // build drops to strip everything but the PRIMARY
437 View Code Duplication
                foreach ($tableDef['keys'] as $keyName => $key) {
438
                    if ($keyName !== 'PRIMARY') {
439
                        $this->queue[] = "ALTER TABLE `{$tableDef['name']}` DROP INDEX {$keyName}";
440
                    }
441
                }
442
            }
443
        } else {
444
            return $this->tableNotEstablished();
445
        }
446
447
        return true;
448
    }
449
450
    /**
451
     * Add drop of PRIMARY key for a table to the work queue
452
     *
453
     * @param string $table table
454
     *
455
     * @return bool true if no errors, false if errors encountered
456
     */
457 View Code Duplication
    public function dropPrimaryKey($table)
458
    {
459
        if (isset($this->tables[$table])) {
460
            $tableDef = $this->tables[$table];
461
            $this->queue[] = "ALTER TABLE `{$tableDef['name']}` DROP PRIMARY KEY ";
462
        } else {
463
            return $this->tableNotEstablished();
464
        }
465
466
        return true;
467
    }
468
469
    /**
470
     * Add drop of table to the work queue
471
     *
472
     * @param string $table table
473
     *
474
     * @return bool true if no errors, false if errors encountered
475
     */
476 View Code Duplication
    public function dropTable($table)
477
    {
478
        if (isset($this->tables[$table])) {
479
            $tableDef = $this->tables[$table];
480
            $this->queue[] = "DROP TABLE `{$tableDef['name']}` ";
481
            unset($this->tables[$table]);
482
        }
483
        // no table is not an error since we are dropping it anyway
484
        return true;
485
    }
486
487
488
    /**
489
     * Add rename table operation to the work queue
490
     *
491
     * @param string $table   table
492
     * @param string $newName new table name
493
     *
494
     * @return bool true if no errors, false if errors encountered
495
     */
496
    public function renameTable($table, $newName)
497
    {
498
        if (isset($this->tables[$table])) {
499
            $tableDef = $this->tables[$table];
500
            $newTable = $this->name($newName);
501
            $this->queue[] = "ALTER TABLE `{$tableDef['name']}` RENAME TO `{$newTable}`";
502
            $tableDef['name'] = $newTable;
503
            $this->tables[$newName] = $tableDef;
504
            unset($this->tables[$table]);
505
        } else {
506
            return $this->tableNotEstablished();
507
        }
508
509
        return true;
510
    }
511
512
    /**
513
     * Add alter table table_options (ENGINE, DEFAULT CHARSET, etc.)
514
     * to work queue
515
     *
516
     * @param string $table   table
517
     * @param array  $options table_options
518
     *
519
     * @return bool true if no errors, false if errors encountered
520
     */
521
    public function setTableOptions($table, $options)
522
    {
523
        if (isset($this->tables[$table])) {
524
            $tableDef = &$this->tables[$table];
525
            // Is this on a table we are adding?
526
            if (isset($tableDef['create']) && $tableDef['create']) {
527
                $tableDef['options'] = $options;
528
                return true;
529
            } else {
530
                $this->queue[] = "ALTER TABLE `{$tableDef['name']}` {$options} ";
531
                $tableDef['options'] = $options;
532
                return true;
533
            }
534
        } else {
535
            return $this->tableNotEstablished();
536
        }
537
    }
538
539
540
    /**
541
     * Clear the work queue
542
     *
543
     * @return void
544
     */
545
    public function resetQueue()
546
    {
547
        $this->tables = array();
548
        $this->queue  = array();
549
    }
550
551
    /**
552
     * Executes the work queue
553
     *
554
     * @param bool $force true to force updates even if this is a 'GET' request
555
     *
556
     * @return bool true if no errors, false if errors encountered
557
     */
558
    public function executeQueue($force = false)
559
    {
560
        $this->expandQueue();
561
        foreach ($this->queue as &$ddl) {
562 View Code Duplication
            if (is_array($ddl)) {
563
                if (isset($ddl['createtable'])) {
564
                    $ddl = $this->renderTableCreate($ddl['createtable']);
565
                }
566
            }
567
            $result = $this->execSql($ddl, $force);
568
            if (!$result) {
569
                $this->lastError = $this->db->error();
570
                $this->lastErrNo = $this->db->errno();
571
572
                return false;
573
            }
574
        }
575
576
        return true;
577
    }
578
579
580
    /**
581
     * Create a DELETE statement and add it to the work queue
582
     *
583
     * @param string                 $table    table
584
     * @param string|CriteriaElement $criteria string where clause or object criteria
585
     *
586
     * @return bool true if no errors, false if errors encountered
587
     */
588
    public function delete($table, $criteria)
589
    {
590
        if (isset($this->tables[$table])) {
591
            $tableDef = $this->tables[$table];
592
            $where = '';
593
            if (is_scalar($criteria)) {
594
                $where = $criteria;
595
            } elseif (is_object($criteria)) {
596
                $where = $criteria->renderWhere();
597
            }
598
            $this->queue[] = "DELETE FROM `{$tableDef['name']}` {$where}";
599
        } else {
600
            return $this->tableNotEstablished();
601
        }
602
603
        return true;
604
    }
605
606
    /** Create an INSERT SQL statement and add it to the work queue.
607
     *
608
     * @param string $table   table
609
     * @param array  $columns array of 'column'=>'value' entries
610
     *
611
     * @return boolean true if no errors, false if errors encountered
612
     */
613
    public function insert($table, $columns)
614
    {
615
        if (isset($this->tables[$table])) {
616
            $tableDef = $this->tables[$table];
617
            $colSql = '';
618
            $valSql = '';
619 View Code Duplication
            foreach ($tableDef['columns'] as $col) {
620
                $comma = empty($colSql) ? '' : ', ';
621
                if (isset($columns[$col['name']])) {
622
                    $colSql .= $comma . $col['name'];
623
                    $valSql .= $comma . $this->db->quote($columns[$col['name']]);
624
                }
625
            }
626
            $sql = "INSERT INTO `{$tableDef['name']}` ({$colSql}) VALUES({$valSql})";
627
            $this->queue[] = $sql;
628
629
            return true;
630
        } else {
631
            return $this->tableNotEstablished();
632
        }
633
    }
634
635
    /**
636
     * Create an UPDATE SQL statement and add it to the work queue
637
     *
638
     * @param string                 $table    table
639
     * @param array                  $columns  array of 'column'=>'value' entries
640
     * @param string|CriteriaElement $criteria string where clause or object criteria
641
     *
642
     * @return boolean true if no errors, false if errors encountered
643
     */
644
    public function update($table, $columns, $criteria)
645
    {
646
        if (isset($this->tables[$table])) {
647
            $tableDef = $this->tables[$table];
648
            $where = '';
649
            if (is_scalar($criteria)) {
650
                $where = $criteria;
651
            } elseif (is_object($criteria)) {
652
                $where = $criteria->renderWhere();
653
            }
654
            $colSql = '';
655 View Code Duplication
            foreach ($tableDef['columns'] as $col) {
656
                $comma = empty($colSql) ? '' : ', ';
657
                if (isset($columns[$col['name']])) {
658
                    $colSql .= $comma . $col['name'] . ' = '
659
                        . $this->db->quote($columns[$col['name']]);
660
                }
661
            }
662
            $sql = "UPDATE `{$tableDef['name']}` SET {$colSql} {$where}";
663
            $this->queue[] = $sql;
664
665
            return true;
666
        } else {
667
            return $this->tableNotEstablished();
668
        }
669
    }
670
671
    /**
672
     * Add statement to remove all rows from a table to the work queue
673
     *
674
     * @param string $table table
675
     *
676
     * @return bool true if no errors, false if errors encountered
677
     */
678 View Code Duplication
    public function truncate($table)
679
    {
680
        if (isset($this->tables[$table])) {
681
            $tableDef = $this->tables[$table];
682
            $this->queue[] = "TRUNCATE TABLE `{$tableDef['name']}`";
683
        } else {
684
            return $this->tableNotEstablished();
685
        }
686
687
        return true;
688
    }
689
690
691
692
    /**
693
     * return SQL to create the table
694
     *
695
     * This method does NOT modify the work queue
696
     *
697
     * @param string $table    table
698
     * @param bool   $prefixed true to return with table name prefixed
699
     *
700
     * @return string|false string SQL to create table, or false if errors encountered
0 ignored issues
show
Documentation introduced by
Should the return type not be string|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
701
     */
702
    protected function renderTableCreate($table, $prefixed = false)
703
    {
704
        if (isset($this->tables[$table])) {
705
            $tableDef = $this->tables[$table];
706
            $tableName = ($prefixed ? $tableDef['name'] : $table);
707
            $sql = "CREATE TABLE `{$tableName}` (";
708
            $firstComma = '';
709
            foreach ($tableDef['columns'] as $col) {
710
                $sql .= "{$firstComma}\n    `{$col['name']}`  {$col['attributes']}";
711
                $firstComma = ',';
712
            }
713
            $keySql = '';
714
            foreach ($tableDef['keys'] as $keyName => $key) {
715
                if ($keyName === 'PRIMARY') {
716
                    $keySql .= ",\n  PRIMARY KEY ({$key['columns']})";
717
                } else {
718
                    $unique = $key['unique'] ? 'UNIQUE ' : '';
719
                    $keySql .= ",\n  {$unique}KEY {$keyName} ({$key['columns']})";
720
                }
721
            }
722
            $sql .= $keySql;
723
            $sql .= "\n) {$tableDef['options']};\n";
724
725
            return $sql;
726
        } else {
727
            return $this->tableNotEstablished();
728
        }
729
    }
730
731
    /**
732
     * execute an SQL statement
733
     *
734
     * @param string $sql   SQL statement to execute
735
     * @param bool   $force true to use force updates even in safe requests
736
     *
737
     * @return mixed result resource if no error,
738
     *               true if no error but no result
739
     *               false if error encountered.
740
     *               Any error message is in $this->lastError;
741
     */
742
    protected function execSql($sql, $force = false)
743
    {
744
        if ($force) {
745
            $result = $this->db->queryF($sql);
746
        } else {
747
            $result = $this->db->query($sql);
748
        }
749
750
        if (!$result) {
751
            $this->lastError = $this->db->error();
752
            $this->lastErrNo = $this->db->errno();
753
        }
754
755
        return $result;
756
    }
757
758
    /**
759
     * fetch the next row of a result set
760
     *
761
     * @param resource $result as returned by query
762
     *
763
     * @return mixed false on error
764
     */
765
    protected function fetch($result)
766
    {
767
        return $this->db->fetchArray($result);
768
    }
769
770
    /**
771
     * get table definition from INFORMATION_SCHEMA
772
     *
773
     * @param string $table table
774
     *
775
     * @return array|bool table definition array if table exists, true if table not defined, or
776
     *                    false on error. Error message in $this->lastError;
777
     */
778
    protected function getTable($table)
779
    {
780
        $tableDef = array();
781
782
        $sql  = 'SELECT TABLE_NAME, ENGINE, CHARACTER_SET_NAME ';
783
        $sql .= ' FROM `INFORMATION_SCHEMA`.`TABLES` t, ';
784
        $sql .= ' `INFORMATION_SCHEMA`.`COLLATIONS` c ';
785
        $sql .= ' WHERE t.TABLE_SCHEMA = \'' . $this->databaseName . '\' ';
786
        $sql .= ' AND t.TABLE_NAME = \'' . $this->name($table) . '\' ';
787
        $sql .= ' AND t.TABLE_COLLATION  = c.COLLATION_NAME ';
788
789
        $result = $this->execSql($sql);
790
        if (!$result) {
791
            return false;
792
        }
793
        $tableSchema = $this->fetch($result);
794
        if (empty($tableSchema)) {
795
            return true;
796
        }
797
        $tableDef['name'] = $tableSchema['TABLE_NAME'];
798
        $tableDef['options'] = 'ENGINE=' . $tableSchema['ENGINE'] . ' '
799
            . 'DEFAULT CHARSET=' . $tableSchema['CHARACTER_SET_NAME'];
800
801
        $sql  = 'SELECT * ';
802
        $sql .= ' FROM `INFORMATION_SCHEMA`.`COLUMNS` ';
803
        $sql .= ' WHERE TABLE_SCHEMA = \'' . $this->databaseName . '\' ';
804
        $sql .= ' AND TABLE_NAME = \'' . $this->name($table) . '\' ';
805
        $sql .= ' ORDER BY `ORDINAL_POSITION` ';
806
807
        $result = $this->execSql($sql);
808
809
        while ($column = $this->fetch($result)) {
810
            $attributes = ' ' . $column['COLUMN_TYPE'] . ' '
811
                . (($column['IS_NULLABLE'] === 'NO') ? ' NOT NULL ' : '')
812
                . (($column['COLUMN_DEFAULT'] === null) ? '' : " DEFAULT '" . $column['COLUMN_DEFAULT'] . "' ")
813
                . $column['EXTRA'];
814
815
            $columnDef = array(
816
                'name' => $column['COLUMN_NAME'],
817
                'attributes' => $attributes
818
            );
819
820
            $tableDef['columns'][] = $columnDef;
821
        };
822
823
        $sql  = 'SELECT `INDEX_NAME`, `SEQ_IN_INDEX`, `NON_UNIQUE`, ';
824
        $sql .= ' `COLUMN_NAME`, `SUB_PART` ';
825
        $sql .= ' FROM `INFORMATION_SCHEMA`.`STATISTICS` ';
826
        $sql .= ' WHERE TABLE_SCHEMA = \'' . $this->databaseName . '\' ';
827
        $sql .= ' AND TABLE_NAME = \'' . $this->name($table) . '\' ';
828
        $sql .= ' ORDER BY `INDEX_NAME`, `SEQ_IN_INDEX` ';
829
830
        $result = $this->execSql($sql);
831
832
        $lastKey = '';
833
        $keyCols = '';
834
        $keyUnique = false;
835
        while ($key = $this->fetch($result)) {
836
            if ($lastKey != $key['INDEX_NAME']) {
837 View Code Duplication
                if (!empty($lastKey)) {
838
                    $tableDef['keys'][$lastKey]['columns'] = $keyCols;
839
                    $tableDef['keys'][$lastKey]['unique'] = $keyUnique;
840
                }
841
                $lastKey = $key['INDEX_NAME'];
842
                $keyCols = $key['COLUMN_NAME'];
843
                if (!empty($key['SUB_PART'])) {
844
                    $keyCols .= ' (' . $key['SUB_PART'] . ')';
845
                }
846
                $keyUnique = !$key['NON_UNIQUE'];
847
            } else {
848
                $keyCols .= ', ' . $key['COLUMN_NAME'];
849
                if (!empty($key['SUB_PART'])) {
850
                    $keyCols .= ' (' . $key['SUB_PART'] . ')';
851
                }
852
            }
853
        };
854 View Code Duplication
        if (!empty($lastKey)) {
855
            $tableDef['keys'][$lastKey]['columns'] = $keyCols;
856
            $tableDef['keys'][$lastKey]['unique'] = $keyUnique;
857
        }
858
859
        return $tableDef;
860
    }
861
862
    /**
863
     * During processing, tables to be created are put in the queue as
864
     * an array('createtable' => tablename) since the definition is not
865
     * complete. This method will expand those references to the full
866
     * ddl to create the table.
867
     *
868
     * @return void
869
     */
870
    protected function expandQueue()
871
    {
872
        foreach ($this->queue as &$ddl) {
873 View Code Duplication
            if (is_array($ddl)) {
874
                if (isset($ddl['createtable'])) {
875
                    $ddl = $this->renderTableCreate($ddl['createtable'], true);
876
                }
877
            }
878
        }
879
    }
880
881
    /**
882
     * Return message from last error encountered
883
     *
884
     * @return string last error message
885
     */
886
    public function getLastError()
887
    {
888
        return $this->lastError;
889
    }
890
891
    /**
892
     * Return code from last error encountered
893
     *
894
     * @return int last error number
895
     */
896
    public function getLastErrNo()
897
    {
898
        return $this->lastErrNo;
899
    }
900
901
    /**
902
     * dumpTables - development function to dump raw tables array
903
     *
904
     * @return array tables
905
     */
906
    public function dumpTables()
907
    {
908
        return $this->tables;
909
    }
910
911
    /**
912
     * dumpQueue - development function to dump the work queue
913
     *
914
     * @return array work queue
915
     */
916
    public function dumpQueue()
917
    {
918
        $this->expandQueue();
919
920
        return $this->queue;
921
    }
922
923
    /**
924
     * Set lastError as table not established
925
     *
926
     * @return false
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
927
     */
928
    protected function tableNotEstablished()
929
    {
930
        $this->lastError = _DB_XMF_TABLE_IS_NOT_DEFINED;
931
        $this->lastErrNo = -1;
932
        return false;
933
    }
934
}
935