Passed
Push — master ( 94652f...ff593e )
by William
03:47
created

CreateStatement   F

Complexity

Total Complexity 85

Size/Duplication

Total Lines 774
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 372
dl 0
loc 774
ccs 195
cts 195
cp 1
rs 2
c 3
b 1
f 0
wmc 85

2 Methods

Rating   Name   Duplication   Size   Complexity  
F build() 0 107 23
F parse() 0 267 62

How to fix   Complexity   

Complex Class

Complex classes like CreateStatement often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CreateStatement, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser\Statements;
6
7
use PhpMyAdmin\SqlParser\Components\ArrayObj;
8
use PhpMyAdmin\SqlParser\Components\CreateDefinition;
9
use PhpMyAdmin\SqlParser\Components\DataType;
10
use PhpMyAdmin\SqlParser\Components\Expression;
11
use PhpMyAdmin\SqlParser\Components\OptionsArray;
12
use PhpMyAdmin\SqlParser\Components\ParameterDefinition;
13
use PhpMyAdmin\SqlParser\Components\PartitionDefinition;
14
use PhpMyAdmin\SqlParser\Parser;
15
use PhpMyAdmin\SqlParser\Statement;
16
use PhpMyAdmin\SqlParser\Token;
17
use PhpMyAdmin\SqlParser\TokensList;
18
19
use function is_array;
20
use function trim;
21
22
/**
23
 * `CREATE` statement.
24
 */
25
class CreateStatement extends Statement
26
{
27
    /**
28
     * Options for `CREATE` statements.
29
     *
30
     * @var array<string, int|array<int, int|string>>
31
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
32
     */
33
    public static $OPTIONS = [
34
        // CREATE TABLE
35
        'TEMPORARY' => 1,
36
37
        // CREATE VIEW
38
        'OR REPLACE' => 2,
39
        'ALGORITHM' => [
40
            3,
41
            'var=',
42
        ],
43
        // `DEFINER` is also used for `CREATE FUNCTION / PROCEDURE`
44
        'DEFINER' => [
45
            4,
46
            'expr=',
47
        ],
48
        // Used in `CREATE VIEW`
49
        'SQL SECURITY' => [
50
            5,
51
            'var',
52
        ],
53
54
        'DATABASE' => 6,
55
        'EVENT' => 6,
56
        'FUNCTION' => 6,
57
        'INDEX' => 6,
58
        'UNIQUE INDEX' => 6,
59
        'FULLTEXT INDEX' => 6,
60
        'SPATIAL INDEX' => 6,
61
        'PROCEDURE' => 6,
62
        'SERVER' => 6,
63
        'TABLE' => 6,
64
        'TABLESPACE' => 6,
65
        'TRIGGER' => 6,
66
        'USER' => 6,
67
        'VIEW' => 6,
68
        'SCHEMA' => 6,
69
70
        // CREATE TABLE
71
        'IF NOT EXISTS' => 7,
72
    ];
73
74
    /**
75
     * All database options.
76
     *
77
     * @var array<string, int|array<int, int|string>>
78
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
79
     */
80
    public static $DB_OPTIONS = [
81
        'CHARACTER SET' => [
82
            1,
83
            'var=',
84
        ],
85
        'CHARSET' => [
86
            1,
87
            'var=',
88
        ],
89
        'DEFAULT CHARACTER SET' => [
90
            1,
91
            'var=',
92
        ],
93
        'DEFAULT CHARSET' => [
94
            1,
95
            'var=',
96
        ],
97
        'DEFAULT COLLATE' => [
98
            2,
99
            'var=',
100
        ],
101
        'COLLATE' => [
102
            2,
103
            'var=',
104
        ],
105
    ];
106
107
    /**
108
     * All table options.
109
     *
110
     * @var array<string, int|array<int, int|string>>
111
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
112
     */
113
    public static $TABLE_OPTIONS = [
114
        'ENGINE' => [
115
            1,
116
            'var=',
117
        ],
118
        'AUTO_INCREMENT' => [
119
            2,
120
            'var=',
121
        ],
122
        'AVG_ROW_LENGTH' => [
123
            3,
124
            'var',
125
        ],
126
        'CHARACTER SET' => [
127
            4,
128
            'var=',
129
        ],
130
        'CHARSET' => [
131
            4,
132
            'var=',
133
        ],
134
        'DEFAULT CHARACTER SET' => [
135
            4,
136
            'var=',
137
        ],
138
        'DEFAULT CHARSET' => [
139
            4,
140
            'var=',
141
        ],
142
        'CHECKSUM' => [
143
            5,
144
            'var',
145
        ],
146
        'DEFAULT COLLATE' => [
147
            6,
148
            'var=',
149
        ],
150
        'COLLATE' => [
151
            6,
152
            'var=',
153
        ],
154
        'COMMENT' => [
155
            7,
156
            'var=',
157
        ],
158
        'CONNECTION' => [
159
            8,
160
            'var',
161
        ],
162
        'DATA DIRECTORY' => [
163
            9,
164
            'var',
165
        ],
166
        'DELAY_KEY_WRITE' => [
167
            10,
168
            'var',
169
        ],
170
        'INDEX DIRECTORY' => [
171
            11,
172
            'var',
173
        ],
174
        'INSERT_METHOD' => [
175
            12,
176
            'var',
177
        ],
178
        'KEY_BLOCK_SIZE' => [
179
            13,
180
            'var',
181
        ],
182
        'MAX_ROWS' => [
183
            14,
184
            'var',
185
        ],
186
        'MIN_ROWS' => [
187
            15,
188
            'var',
189
        ],
190
        'PACK_KEYS' => [
191
            16,
192
            'var',
193
        ],
194
        'PASSWORD' => [
195
            17,
196
            'var',
197
        ],
198
        'ROW_FORMAT' => [
199
            18,
200
            'var',
201
        ],
202
        'TABLESPACE' => [
203
            19,
204
            'var',
205
        ],
206
        'STORAGE' => [
207
            20,
208
            'var',
209
        ],
210
        'UNION' => [
211
            21,
212
            'var',
213
        ],
214
    ];
215
216
    /**
217
     * All function options.
218
     *
219
     * @var array<string, int|array<int, int|string>>
220
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
221
     */
222
    public static $FUNC_OPTIONS = [
223
        'NOT' => [
224
            2,
225
            'var',
226
        ],
227
        'FUNCTION' => [
228
            3,
229
            'var=',
230
        ],
231
        'PROCEDURE' => [
232
            3,
233
            'var=',
234
        ],
235
        'CONTAINS' => [
236
            4,
237
            'expr',
238
        ],
239
        'NO' => [
240
            4,
241
            'var',
242
        ],
243
        'READS' => [
244
            4,
245
            'var',
246
        ],
247
        'MODIFIES' => [
248
            4,
249
            'expr',
250
        ],
251
        'SQL SECURITY' => [
252
            6,
253
            'var',
254
        ],
255
        'LANGUAGE' => [
256
            7,
257
            'var',
258
        ],
259
        'COMMENT' => [
260
            8,
261
            'var',
262
        ],
263
264
        'CREATE' => 1,
265
        'DETERMINISTIC' => 2,
266
        'DATA' => 5,
267
    ];
268
269
    /**
270
     * All trigger options.
271
     *
272
     * @var array<string, int|array<int, int|string>>
273
     * @psalm-var array<string, (positive-int|array{positive-int, ('var'|'var='|'expr'|'expr=')})>
274
     */
275
    public static $TRIGGER_OPTIONS = [
276
        'BEFORE' => 1,
277
        'AFTER' => 1,
278
        'INSERT' => 2,
279
        'UPDATE' => 2,
280
        'DELETE' => 2,
281
    ];
282
283
    /**
284
     * The name of the entity that is created.
285
     *
286
     * Used by all `CREATE` statements.
287
     *
288
     * @var Expression|null
289
     */
290
    public $name;
291
292
    /**
293
     * The options of the entity (table, procedure, function, etc.).
294
     *
295
     * Used by `CREATE TABLE`, `CREATE FUNCTION` and `CREATE PROCEDURE`.
296
     *
297
     * @see static::$TABLE_OPTIONS
298
     * @see static::$FUNC_OPTIONS
299
     * @see static::$TRIGGER_OPTIONS
300
     *
301
     * @var OptionsArray|null
302
     */
303
    public $entityOptions;
304
305
    /**
306
     * If `CREATE TABLE`, a list of columns and keys.
307
     * If `CREATE VIEW`, a list of columns.
308
     *
309
     * Used by `CREATE TABLE` and `CREATE VIEW`.
310
     *
311
     * @var CreateDefinition[]|ArrayObj|null
312
     */
313
    public $fields;
314
315
    /**
316
     * If `CREATE TABLE WITH`.
317
     * If `CREATE TABLE AS WITH`.
318
     * If `CREATE VIEW AS WITH`.
319
     *
320
     * Used by `CREATE TABLE`, `CREATE VIEW`
321
     *
322
     * @var WithStatement|null
323
     */
324
    public $with;
325
326
    /**
327
     * If `CREATE TABLE ... SELECT`.
328
     * If `CREATE VIEW AS ` ... SELECT`.
329
     *
330
     * Used by `CREATE TABLE`, `CREATE VIEW`
331
     *
332
     * @var SelectStatement|null
333
     */
334
    public $select;
335
336
    /**
337
     * If `CREATE TABLE ... LIKE`.
338
     *
339
     * Used by `CREATE TABLE`
340
     *
341
     * @var Expression|null
342
     */
343
    public $like;
344
345
    /**
346
     * Expression used for partitioning.
347
     *
348
     * @var string|null
349
     */
350
    public $partitionBy;
351
352
    /**
353
     * The number of partitions.
354
     *
355
     * @var int|null
356
     */
357
    public $partitionsNum;
358
359
    /**
360
     * Expression used for subpartitioning.
361
     *
362
     * @var string|null
363
     */
364
    public $subpartitionBy;
365
366
    /**
367
     * The number of subpartitions.
368
     *
369
     * @var int|null
370
     */
371
    public $subpartitionsNum;
372
373
    /**
374
     * The partition of the new table.
375
     *
376
     * @var PartitionDefinition[]|null
377
     */
378
    public $partitions;
379
380
    /**
381
     * If `CREATE TRIGGER` the name of the table.
382
     *
383
     * Used by `CREATE TRIGGER`.
384
     *
385
     * @var Expression|null
386
     */
387
    public $table;
388
389
    /**
390
     * The return data type of this routine.
391
     *
392
     * Used by `CREATE FUNCTION`.
393
     *
394
     * @var DataType|null
395
     */
396
    public $return;
397
398
    /**
399
     * The parameters of this routine.
400
     *
401
     * Used by `CREATE FUNCTION` and `CREATE PROCEDURE`.
402
     *
403
     * @var ParameterDefinition[]|null
404
     */
405
    public $parameters;
406
407
    /**
408
     * The body of this function or procedure.
409
     * For views, it is the select statement that creates the view.
410
     * Used by `CREATE FUNCTION`, `CREATE PROCEDURE` and `CREATE VIEW`.
411
     *
412
     * @var Token[]|string
413
     */
414
    public $body = [];
415
416
    /**
417
     * @return string
418
     */
419 72
    public function build()
420
    {
421 72
        $fields = '';
422 72
        if (! empty($this->fields)) {
423 40
            if (is_array($this->fields)) {
424 36
                $fields = CreateDefinition::build($this->fields) . ' ';
425 4
            } elseif ($this->fields instanceof ArrayObj) {
0 ignored issues
show
introduced by
$this->fields is always a sub-type of PhpMyAdmin\SqlParser\Components\ArrayObj.
Loading history...
426 4
                $fields = ArrayObj::build($this->fields);
427
            }
428
        }
429
430 72
        if ($this->options->has('DATABASE') || $this->options->has('SCHEMA')) {
0 ignored issues
show
Bug introduced by
The method has() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

430
        if ($this->options->/** @scrutinizer ignore-call */ has('DATABASE') || $this->options->has('SCHEMA')) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
431
            return 'CREATE '
432 4
                . OptionsArray::build($this->options) . ' '
433 4
                . Expression::build($this->name) . ' '
434 4
                . OptionsArray::build($this->entityOptions);
435
        }
436
437 68
        if ($this->options->has('TABLE')) {
438 40
            if ($this->select !== null) {
439
                return 'CREATE '
440 4
                    . OptionsArray::build($this->options) . ' '
441 4
                    . Expression::build($this->name) . ' '
442 4
                    . $this->select->build();
443
            }
444
445 36
            if ($this->like !== null) {
446
                return 'CREATE '
447 4
                    . OptionsArray::build($this->options) . ' '
448 4
                    . Expression::build($this->name) . ' LIKE '
449 4
                    . Expression::build($this->like);
450
            }
451
452 36
            if ($this->with !== null) {
453
                return 'CREATE '
454 4
                . OptionsArray::build($this->options) . ' '
455 4
                . Expression::build($this->name) . ' '
456 4
                . $this->with->build();
457
            }
458
459 36
            $partition = '';
460
461 36
            if (! empty($this->partitionBy)) {
462 12
                $partition .= "\nPARTITION BY " . $this->partitionBy;
463
            }
464
465 36
            if (! empty($this->partitionsNum)) {
466 4
                $partition .= "\nPARTITIONS " . $this->partitionsNum;
467
            }
468
469 36
            if (! empty($this->subpartitionBy)) {
470 8
                $partition .= "\nSUBPARTITION BY " . $this->subpartitionBy;
471
            }
472
473 36
            if (! empty($this->subpartitionsNum)) {
474 4
                $partition .= "\nSUBPARTITIONS " . $this->subpartitionsNum;
475
            }
476
477 36
            if (! empty($this->partitions)) {
478 12
                $partition .= "\n" . PartitionDefinition::build($this->partitions);
479
            }
480
481
            return 'CREATE '
482 36
                . OptionsArray::build($this->options) . ' '
483 36
                . Expression::build($this->name) . ' '
484
                . $fields
485 36
                . OptionsArray::build($this->entityOptions)
486
                . $partition;
487 28
        } elseif ($this->options->has('VIEW')) {
488 8
            $builtStatement = '';
489 8
            if ($this->select !== null) {
490 4
                $builtStatement = $this->select->build();
491 8
            } elseif ($this->with !== null) {
492 8
                $builtStatement = $this->with->build();
493
            }
494
495
            return 'CREATE '
496 8
                . OptionsArray::build($this->options) . ' '
497 8
                . Expression::build($this->name) . ' '
498
                . $fields . ' AS ' . $builtStatement
499 8
                . (! empty($this->body) ? TokensList::build($this->body) : '') . ' '
500 8
                . OptionsArray::build($this->entityOptions);
501 20
        } elseif ($this->options->has('TRIGGER')) {
502
            return 'CREATE '
503 4
                . OptionsArray::build($this->options) . ' '
504 4
                . Expression::build($this->name) . ' '
505 4
                . OptionsArray::build($this->entityOptions) . ' '
506 4
                . 'ON ' . Expression::build($this->table) . ' '
507 4
                . 'FOR EACH ROW ' . TokensList::build($this->body);
508 16
        } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) {
509 12
            $tmp = '';
510 12
            if ($this->options->has('FUNCTION')) {
511 8
                $tmp = 'RETURNS ' . DataType::build($this->return);
512
            }
513
514
            return 'CREATE '
515 12
                . OptionsArray::build($this->options) . ' '
516 12
                . Expression::build($this->name) . ' '
517 12
                . ParameterDefinition::build($this->parameters) . ' '
518 12
                . $tmp . ' ' . OptionsArray::build($this->entityOptions) . ' '
519 12
                . TokensList::build($this->body);
520
        }
521
522
        return 'CREATE '
523 4
            . OptionsArray::build($this->options) . ' '
524 4
            . Expression::build($this->name) . ' '
525 4
            . TokensList::build($this->body);
526
    }
527
528
    /**
529
     * @param Parser     $parser the instance that requests parsing
530
     * @param TokensList $list   the list of tokens to be parsed
531
     */
532 348
    public function parse(Parser $parser, TokensList $list)
533
    {
534 348
        ++$list->idx; // Skipping `CREATE`.
535
536
        // Parsing options.
537 348
        $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
538 348
        ++$list->idx; // Skipping last option.
539
540 348
        $isDatabase = $this->options->has('DATABASE') || $this->options->has('SCHEMA');
541 348
        $fieldName = $isDatabase ? 'database' : 'table';
542
543
        // Parsing the field name.
544 348
        $this->name = Expression::parse(
545
            $parser,
546
            $list,
547
            [
548
                'parseField' => $fieldName,
549
                'breakOnAlias' => true,
550
            ]
551
        );
552
553 348
        if (! isset($this->name) || ($this->name === '')) {
554 4
            $parser->error('The name of the entity was expected.', $list->tokens[$list->idx]);
555
        } else {
556 344
            ++$list->idx; // Skipping field.
557
        }
558
559
        /**
560
         * Token parsed at this moment.
561
         */
562 348
        $token = $list->tokens[$list->idx];
563 348
        $nextidx = $list->idx + 1;
564 348
        while ($nextidx < $list->count && $list->tokens[$nextidx]->type === Token::TYPE_WHITESPACE) {
565 208
            ++$nextidx;
566
        }
567
568 348
        if ($isDatabase) {
569 20
            $this->entityOptions = OptionsArray::parse($parser, $list, static::$DB_OPTIONS);
570 328
        } elseif ($this->options->has('TABLE')) {
571 200
            if (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SELECT')) {
572
                /* CREATE TABLE ... SELECT */
573 8
                $this->select = new SelectStatement($parser, $list);
574 192
            } elseif ($token->type === Token::TYPE_KEYWORD && ($token->keyword === 'WITH')) {
575
                /* CREATE TABLE WITH */
576 24
                $this->with = new WithStatement($parser, $list);
577
            } elseif (
578 172
                ($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'AS')
579 172
                && ($list->tokens[$nextidx]->type === Token::TYPE_KEYWORD)
580
            ) {
581 8
                if ($list->tokens[$nextidx]->value === 'SELECT') {
582
                    /* CREATE TABLE ... AS SELECT */
583 4
                    $list->idx = $nextidx;
584 4
                    $this->select = new SelectStatement($parser, $list);
585 4
                } elseif ($list->tokens[$nextidx]->value === 'WITH') {
586
                    /* CREATE TABLE WITH */
587 4
                    $list->idx = $nextidx;
588 8
                    $this->with = new WithStatement($parser, $list);
589
                }
590 164
            } elseif ($token->type === Token::TYPE_KEYWORD && $token->keyword === 'LIKE') {
591
                /* CREATE TABLE `new_tbl` LIKE 'orig_tbl' */
592 12
                $list->idx = $nextidx;
593 12
                $this->like = Expression::parse(
594
                    $parser,
595
                    $list,
596
                    [
597
                        'parseField' => 'table',
598
                        'breakOnAlias' => true,
599
                    ]
600
                );
601
                // The 'LIKE' keyword was found, but no table_name was found next to it
602 12
                if ($this->like === null) {
603 12
                    $parser->error('A table name was expected.', $list->tokens[$list->idx]);
604
                }
605
            } else {
606 156
                $this->fields = CreateDefinition::parse($parser, $list);
607 156
                if (empty($this->fields)) {
608 12
                    $parser->error('At least one column definition was expected.', $list->tokens[$list->idx]);
609
                }
610
611 156
                ++$list->idx;
612
613 156
                $this->entityOptions = OptionsArray::parse($parser, $list, static::$TABLE_OPTIONS);
614
615
                /**
616
                 * The field that is being filled (`partitionBy` or
617
                 * `subpartitionBy`).
618
                 *
619
                 * @var string
620
                 */
621 156
                $field = null;
622
623
                /**
624
                 * The number of brackets. `false` means no bracket was found
625
                 * previously. At least one bracket is required to validate the
626
                 * expression.
627
                 *
628
                 * @var int|bool
629
                 */
630 156
                $brackets = false;
631
632
                /*
633
                 * Handles partitions.
634
                 */
635 200
                for (; $list->idx < $list->count; ++$list->idx) {
636
                    /**
637
                     * Token parsed at this moment.
638
                     */
639 156
                    $token = $list->tokens[$list->idx];
640
641
                    // End of statement.
642 156
                    if ($token->type === Token::TYPE_DELIMITER) {
643 124
                        break;
644
                    }
645
646
                    // Skipping comments.
647 156
                    if ($token->type === Token::TYPE_COMMENT) {
648 4
                        continue;
649
                    }
650
651 156
                    if (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'PARTITION BY')) {
652 20
                        $field = 'partitionBy';
653 20
                        $brackets = false;
654 156
                    } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SUBPARTITION BY')) {
655 16
                        $field = 'subpartitionBy';
656 16
                        $brackets = false;
657 156
                    } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'PARTITIONS')) {
658 8
                        $token = $list->getNextOfType(Token::TYPE_NUMBER);
659 8
                        --$list->idx; // `getNextOfType` also advances one position.
660 8
                        $this->partitionsNum = $token->value;
661 156
                    } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SUBPARTITIONS')) {
662 8
                        $token = $list->getNextOfType(Token::TYPE_NUMBER);
663 8
                        --$list->idx; // `getNextOfType` also advances one position.
664 8
                        $this->subpartitionsNum = $token->value;
665 156
                    } elseif (! empty($field)) {
666
                        /*
667
                         * Handling the content of `PARTITION BY` and `SUBPARTITION BY`.
668
                         */
669
670
                        // Counting brackets.
671 20
                        if ($token->type === Token::TYPE_OPERATOR) {
672 20
                            if ($token->value === '(') {
673
                                // This is used instead of `++$brackets` because,
674
                                // initially, `$brackets` is `false` cannot be
675
                                // incremented.
676 20
                                $brackets += 1;
677 20
                            } elseif ($token->value === ')') {
678 20
                                --$brackets;
679
                            }
680
                        }
681
682
                        // Building the expression used for partitioning.
683 20
                        $this->$field .= $token->type === Token::TYPE_WHITESPACE ? ' ' : $token->token;
684
685
                        // Last bracket was read, the expression ended.
686
                        // Comparing with `0` and not `false`, because `false` means
687
                        // that no bracket was found and at least one must is
688
                        // required.
689 20
                        if ($brackets === 0) {
690 20
                            $this->$field = trim($this->$field);
691 20
                            $field = null;
692
                        }
693 156
                    } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
694 32
                        if (! empty($this->partitionBy)) {
695 20
                            $this->partitions = ArrayObj::parse(
0 ignored issues
show
Documentation Bug introduced by
It seems like PhpMyAdmin\SqlParser\Com...\PartitionDefinition')) of type PhpMyAdmin\SqlParser\Com...ser\Components\ArrayObj is incompatible with the declared type PhpMyAdmin\SqlParser\Com...titionDefinition[]|null of property $partitions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
696
                                $parser,
697
                                $list,
698
                                ['type' => 'PhpMyAdmin\\SqlParser\\Components\\PartitionDefinition']
699
                            );
700
                        }
701
702 32
                        break;
703
                    }
704
                }
705
            }
706 128
        } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) {
707 56
            $this->parameters = ParameterDefinition::parse($parser, $list);
708 56
            if ($this->options->has('FUNCTION')) {
709 28
                $prevToken = $token;
710 28
                $token = $list->getNextOfType(Token::TYPE_KEYWORD);
711 28
                if ($token === null || $token->keyword !== 'RETURNS') {
712 12
                    $parser->error('A "RETURNS" keyword was expected.', $token ?? $prevToken);
713
                } else {
714 16
                    ++$list->idx;
715 16
                    $this->return = DataType::parse($parser, $list);
716
                }
717
            }
718
719 56
            ++$list->idx;
720
721 56
            $this->entityOptions = OptionsArray::parse($parser, $list, static::$FUNC_OPTIONS);
722 56
            ++$list->idx;
723
724 56
            for (; $list->idx < $list->count; ++$list->idx) {
725 48
                $token = $list->tokens[$list->idx];
726 48
                $this->body[] = $token;
727
            }
728 72
        } elseif ($this->options->has('VIEW')) {
729
            /** @var Token $token */
730 52
            $token = $list->getNext(); // Skipping whitespaces and comments.
731
732
            // Parsing columns list.
733 52
            if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
734 12
                --$list->idx; // getNext() also goes forward one field.
735 12
                $this->fields = ArrayObj::parse($parser, $list);
736 12
                ++$list->idx; // Skipping last token from the array.
737 12
                $list->getNext();
738
            }
739
740
            // Parsing the SELECT expression if the view started with it.
741
            if (
742 52
                $token->type === Token::TYPE_KEYWORD
743 52
                && $token->keyword === 'AS'
744 52
                && $list->tokens[$nextidx]->type === Token::TYPE_KEYWORD
745
            ) {
746 40
                if ($list->tokens[$nextidx]->value === 'SELECT') {
747 28
                    $list->idx = $nextidx;
748 28
                    $this->select = new SelectStatement($parser, $list);
749 28
                    ++$list->idx; // Skipping last token from the select.
750 16
                } elseif ($list->tokens[$nextidx]->value === 'WITH') {
751 16
                    ++$list->idx;
752 16
                    $this->with = new WithStatement($parser, $list);
753
                }
754
            }
755
756
            // Parsing all other tokens
757 52
            for (; $list->idx < $list->count; ++$list->idx) {
758 52
                $token = $list->tokens[$list->idx];
759 52
                if ($token->type === Token::TYPE_DELIMITER) {
760 52
                    break;
761
                }
762
763 28
                $this->body[] = $token;
764
            }
765 20
        } elseif ($this->options->has('TRIGGER')) {
766
            // Parsing the time and the event.
767 4
            $this->entityOptions = OptionsArray::parse($parser, $list, static::$TRIGGER_OPTIONS);
768 4
            ++$list->idx;
769
770 4
            $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'ON');
771 4
            ++$list->idx; // Skipping `ON`.
772
773
            // Parsing the name of the table.
774 4
            $this->table = Expression::parse(
775
                $parser,
776
                $list,
777
                [
778
                    'parseField' => 'table',
779
                    'breakOnAlias' => true,
780
                ]
781
            );
782 4
            ++$list->idx;
783
784 4
            $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'FOR EACH ROW');
785 4
            ++$list->idx; // Skipping `FOR EACH ROW`.
786
787 4
            for (; $list->idx < $list->count; ++$list->idx) {
788 4
                $token = $list->tokens[$list->idx];
789 4
                $this->body[] = $token;
790
            }
791
        } else {
792 16
            for (; $list->idx < $list->count; ++$list->idx) {
793 16
                $token = $list->tokens[$list->idx];
794 16
                if ($token->type === Token::TYPE_DELIMITER) {
795 16
                    break;
796
                }
797
798 4
                $this->body[] = $token;
799
            }
800
        }
801
    }
802
}
803