Passed
Push — master ( 0efc01...ef206b )
by Maurício
02:53
created

CreateStatement   F

Complexity

Total Complexity 80

Size/Duplication

Total Lines 704
Duplicated Lines 0 %

Test Coverage

Coverage 99.48%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 341
c 1
b 1
f 0
dl 0
loc 704
ccs 191
cts 192
cp 0.9948
rs 2
wmc 80

2 Methods

Rating   Name   Duplication   Size   Complexity  
F build() 0 91 20
F parse() 0 259 60

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
 * `CREATE` statement.
4
 */
5
6
declare(strict_types=1);
7
8
namespace PhpMyAdmin\SqlParser\Statements;
9
10
use PhpMyAdmin\SqlParser\Components\ArrayObj;
11
use PhpMyAdmin\SqlParser\Components\CreateDefinition;
12
use PhpMyAdmin\SqlParser\Components\DataType;
13
use PhpMyAdmin\SqlParser\Components\Expression;
14
use PhpMyAdmin\SqlParser\Components\OptionsArray;
15
use PhpMyAdmin\SqlParser\Components\ParameterDefinition;
16
use PhpMyAdmin\SqlParser\Components\PartitionDefinition;
17
use PhpMyAdmin\SqlParser\Parser;
18
use PhpMyAdmin\SqlParser\Statement;
19
use PhpMyAdmin\SqlParser\Token;
20
use PhpMyAdmin\SqlParser\TokensList;
21
22
use function is_array;
23
use function trim;
24
25
/**
26
 * `CREATE` statement.
27
 */
28
class CreateStatement extends Statement
29
{
30
    /**
31
     * Options for `CREATE` statements.
32
     *
33
     * @var array
34
     */
35
    public static $OPTIONS = [
36
        // CREATE TABLE
37
        'TEMPORARY' => 1,
38
39
        // CREATE VIEW
40
        'OR REPLACE' => 2,
41
        'ALGORITHM' => [
42
            3,
43
            'var=',
44
        ],
45
        // `DEFINER` is also used for `CREATE FUNCTION / PROCEDURE`
46
        'DEFINER' => [
47
            4,
48
            'expr=',
49
        ],
50
        'SQL SECURITY' => [
51
            5,
52
            'var',
53
        ],
54
55
        'DATABASE' => 6,
56
        'EVENT' => 6,
57
        'FUNCTION' => 6,
58
        'INDEX' => 6,
59
        'UNIQUE INDEX' => 6,
60
        'FULLTEXT INDEX' => 6,
61
        'SPATIAL INDEX' => 6,
62
        'PROCEDURE' => 6,
63
        'SERVER' => 6,
64
        'TABLE' => 6,
65
        'TABLESPACE' => 6,
66
        'TRIGGER' => 6,
67
        'USER' => 6,
68
        'VIEW' => 6,
69
        'SCHEMA' => 6,
70
71
        // CREATE TABLE
72
        'IF NOT EXISTS' => 7,
73
    ];
74
75
    /**
76
     * All database options.
77
     *
78
     * @var array
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
111
     */
112
    public static $TABLE_OPTIONS = [
113
        'ENGINE' => [
114
            1,
115
            'var=',
116
        ],
117
        'AUTO_INCREMENT' => [
118
            2,
119
            'var=',
120
        ],
121
        'AVG_ROW_LENGTH' => [
122
            3,
123
            'var',
124
        ],
125
        'CHARACTER SET' => [
126
            4,
127
            'var=',
128
        ],
129
        'CHARSET' => [
130
            4,
131
            'var=',
132
        ],
133
        'DEFAULT CHARACTER SET' => [
134
            4,
135
            'var=',
136
        ],
137
        'DEFAULT CHARSET' => [
138
            4,
139
            'var=',
140
        ],
141
        'CHECKSUM' => [
142
            5,
143
            'var',
144
        ],
145
        'DEFAULT COLLATE' => [
146
            6,
147
            'var=',
148
        ],
149
        'COLLATE' => [
150
            6,
151
            'var=',
152
        ],
153
        'COMMENT' => [
154
            7,
155
            'var=',
156
        ],
157
        'CONNECTION' => [
158
            8,
159
            'var',
160
        ],
161
        'DATA DIRECTORY' => [
162
            9,
163
            'var',
164
        ],
165
        'DELAY_KEY_WRITE' => [
166
            10,
167
            'var',
168
        ],
169
        'INDEX DIRECTORY' => [
170
            11,
171
            'var',
172
        ],
173
        'INSERT_METHOD' => [
174
            12,
175
            'var',
176
        ],
177
        'KEY_BLOCK_SIZE' => [
178
            13,
179
            'var',
180
        ],
181
        'MAX_ROWS' => [
182
            14,
183
            'var',
184
        ],
185
        'MIN_ROWS' => [
186
            15,
187
            'var',
188
        ],
189
        'PACK_KEYS' => [
190
            16,
191
            'var',
192
        ],
193
        'PASSWORD' => [
194
            17,
195
            'var',
196
        ],
197
        'ROW_FORMAT' => [
198
            18,
199
            'var',
200
        ],
201
        'TABLESPACE' => [
202
            19,
203
            'var',
204
        ],
205
        'STORAGE' => [
206
            20,
207
            'var',
208
        ],
209
        'UNION' => [
210
            21,
211
            'var',
212
        ],
213
    ];
214
215
    /**
216
     * All function options.
217
     *
218
     * @var array
219
     */
220
    public static $FUNC_OPTIONS = [
221
        'COMMENT' => [
222
            1,
223
            'var=',
224
        ],
225
        'LANGUAGE SQL' => 2,
226
        'DETERMINISTIC' => 3,
227
        'NOT DETERMINISTIC' => 3,
228
        'CONTAINS SQL' => 4,
229
        'NO SQL' => 4,
230
        'READS SQL DATA' => 4,
231
        'MODIFIES SQL DATA' => 4,
232
        'SQL SECURITY DEFINER' => [
233
            5,
234
            'var',
235
        ],
236
    ];
237
238
    /**
239
     * All trigger options.
240
     *
241
     * @var array
242
     */
243
    public static $TRIGGER_OPTIONS = [
244
        'BEFORE' => 1,
245
        'AFTER' => 1,
246
        'INSERT' => 2,
247
        'UPDATE' => 2,
248
        'DELETE' => 2,
249
    ];
250
251
    /**
252
     * The name of the entity that is created.
253
     *
254
     * Used by all `CREATE` statements.
255
     *
256
     * @var Expression
257
     */
258
    public $name;
259
260
    /**
261
     * The options of the entity (table, procedure, function, etc.).
262
     *
263
     * Used by `CREATE TABLE`, `CREATE FUNCTION` and `CREATE PROCEDURE`.
264
     *
265
     * @see static::$TABLE_OPTIONS
266
     * @see static::$FUNC_OPTIONS
267
     * @see static::$TRIGGER_OPTIONS
268
     *
269
     * @var OptionsArray
270
     */
271
    public $entityOptions;
272
273
    /**
274
     * If `CREATE TABLE`, a list of columns and keys.
275
     * If `CREATE VIEW`, a list of columns.
276
     *
277
     * Used by `CREATE TABLE` and `CREATE VIEW`.
278
     *
279
     * @var CreateDefinition[]|ArrayObj
280
     */
281
    public $fields;
282
283
    /**
284
     * If `CREATE TABLE ... SELECT`.
285
     * If `CREATE VIEW AS ` ... SELECT`.
286
     *
287
     * Used by `CREATE TABLE`, `CREATE VIEW`
288
     *
289
     * @var SelectStatement|null
290
     */
291
    public $select;
292
293
    /**
294
     * If `CREATE TABLE ... LIKE`.
295
     *
296
     * Used by `CREATE TABLE`
297
     *
298
     * @var Expression
299
     */
300
    public $like;
301
302
    /**
303
     * Expression used for partitioning.
304
     *
305
     * @var string
306
     */
307
    public $partitionBy;
308
309
    /**
310
     * The number of partitions.
311
     *
312
     * @var int
313
     */
314
    public $partitionsNum;
315
316
    /**
317
     * Expression used for subpartitioning.
318
     *
319
     * @var string
320
     */
321
    public $subpartitionBy;
322
323
    /**
324
     * The number of subpartitions.
325
     *
326
     * @var int
327
     */
328
    public $subpartitionsNum;
329
330
    /**
331
     * The partition of the new table.
332
     *
333
     * @var PartitionDefinition[]
334
     */
335
    public $partitions;
336
337
    /**
338
     * If `CREATE TRIGGER` the name of the table.
339
     *
340
     * Used by `CREATE TRIGGER`.
341
     *
342
     * @var Expression
343
     */
344
    public $table;
345
346
    /**
347
     * The return data type of this routine.
348
     *
349
     * Used by `CREATE FUNCTION`.
350
     *
351
     * @var DataType
352
     */
353
    public $return;
354
355
    /**
356
     * The parameters of this routine.
357
     *
358
     * Used by `CREATE FUNCTION` and `CREATE PROCEDURE`.
359
     *
360
     * @var ParameterDefinition[]
361
     */
362
    public $parameters;
363
364
    /**
365
     * The body of this function or procedure.
366
     * For views, it is the select statement that creates the view.
367
     * Used by `CREATE FUNCTION`, `CREATE PROCEDURE` and `CREATE VIEW`.
368
     *
369
     * @var Token[]|string
370
     */
371
    public $body = [];
372
373
    /**
374
     * @return string
375
     */
376 52
    public function build()
377
    {
378 52
        $fields = '';
379 52
        if (! empty($this->fields)) {
380 32
            if (is_array($this->fields)) {
381 28
                $fields = CreateDefinition::build($this->fields) . ' ';
382 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...
383 4
                $fields = ArrayObj::build($this->fields);
384
            }
385
        }
386
387 52
        if ($this->options->has('DATABASE') || $this->options->has('SCHEMA')) {
388
            return 'CREATE '
389 4
                . OptionsArray::build($this->options) . ' '
390 4
                . Expression::build($this->name) . ' '
391 4
                . OptionsArray::build($this->entityOptions);
392
        }
393
394 48
        if ($this->options->has('TABLE')) {
395 32
            if ($this->select !== null) {
396
                return 'CREATE '
397 4
                    . OptionsArray::build($this->options) . ' '
398 4
                    . Expression::build($this->name) . ' '
399 4
                    . $this->select->build();
400
            }
401
402 28
            if ($this->like !== null) {
403
                return 'CREATE '
404 4
                    . OptionsArray::build($this->options) . ' '
405 4
                    . Expression::build($this->name) . ' LIKE '
406 4
                    . Expression::build($this->like);
407
            }
408
409 28
            $partition = '';
410
411 28
            if (! empty($this->partitionBy)) {
412 12
                $partition .= "\nPARTITION BY " . $this->partitionBy;
413
            }
414
415 28
            if (! empty($this->partitionsNum)) {
416 4
                $partition .= "\nPARTITIONS " . $this->partitionsNum;
417
            }
418
419 28
            if (! empty($this->subpartitionBy)) {
420 8
                $partition .= "\nSUBPARTITION BY " . $this->subpartitionBy;
421
            }
422
423 28
            if (! empty($this->subpartitionsNum)) {
424 4
                $partition .= "\nSUBPARTITIONS " . $this->subpartitionsNum;
425
            }
426
427 28
            if (! empty($this->partitions)) {
428 12
                $partition .= "\n" . PartitionDefinition::build($this->partitions);
429
            }
430
431
            return 'CREATE '
432 28
                . OptionsArray::build($this->options) . ' '
433 28
                . Expression::build($this->name) . ' '
434 28
                . $fields
435 28
                . OptionsArray::build($this->entityOptions)
436 28
                . $partition;
437 16
        } elseif ($this->options->has('VIEW')) {
438
            return 'CREATE '
439 4
                . OptionsArray::build($this->options) . ' '
440 4
                . Expression::build($this->name) . ' '
441 4
                . $fields . ' AS ' . ($this->select ? $this->select->build() : TokensList::build($this->body)) . ' '
442 4
                . OptionsArray::build($this->entityOptions);
443 12
        } elseif ($this->options->has('TRIGGER')) {
444
            return 'CREATE '
445 4
                . OptionsArray::build($this->options) . ' '
446 4
                . Expression::build($this->name) . ' '
447 4
                . OptionsArray::build($this->entityOptions) . ' '
448 4
                . 'ON ' . Expression::build($this->table) . ' '
449 4
                . 'FOR EACH ROW ' . TokensList::build($this->body);
450 8
        } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) {
451 4
            $tmp = '';
452 4
            if ($this->options->has('FUNCTION')) {
453 4
                $tmp = 'RETURNS ' . DataType::build($this->return);
454
            }
455
456
            return 'CREATE '
457 4
                . OptionsArray::build($this->options) . ' '
458 4
                . Expression::build($this->name) . ' '
459 4
                . ParameterDefinition::build($this->parameters) . ' '
460 4
                . $tmp . ' ' . TokensList::build($this->body);
461
        }
462
463
        return 'CREATE '
464 4
            . OptionsArray::build($this->options) . ' '
465 4
            . Expression::build($this->name) . ' '
466 4
            . TokensList::build($this->body);
467
    }
468
469
    /**
470
     * @param Parser     $parser the instance that requests parsing
471
     * @param TokensList $list   the list of tokens to be parsed
472
     */
473 260
    public function parse(Parser $parser, TokensList $list)
474
    {
475 260
        ++$list->idx; // Skipping `CREATE`.
476
477
        // Parsing options.
478 260
        $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
479 260
        ++$list->idx; // Skipping last option.
480
481 260
        $isDatabase = $this->options->has('DATABASE') || $this->options->has('SCHEMA');
482 260
        $fieldName = $isDatabase ? 'database' : 'table';
483
484
        // Parsing the field name.
485 260
        $this->name = Expression::parse(
486 260
            $parser,
487 260
            $list,
488
            [
489 260
                'parseField' => $fieldName,
490
                'breakOnAlias' => true,
491
            ]
492
        );
493
494 260
        if (! isset($this->name) || ($this->name === '')) {
495 4
            $parser->error('The name of the entity was expected.', $list->tokens[$list->idx]);
496
        } else {
497 256
            ++$list->idx; // Skipping field.
498
        }
499
500
        /**
501
         * Token parsed at this moment.
502
         *
503
         * @var Token
504
         */
505 260
        $token = $list->tokens[$list->idx];
506 260
        $nextidx = $list->idx + 1;
507 260
        while ($nextidx < $list->count && $list->tokens[$nextidx]->type === Token::TYPE_WHITESPACE) {
508 144
            ++$nextidx;
509
        }
510
511 260
        if ($isDatabase) {
512 20
            $this->entityOptions = OptionsArray::parse($parser, $list, static::$DB_OPTIONS);
513 240
        } elseif ($this->options->has('TABLE')) {
514 152
            if (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SELECT')) {
515
                /* CREATE TABLE ... SELECT */
516 8
                $this->select = new SelectStatement($parser, $list);
517
            } elseif (
518 144
                ($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'AS')
519 144
                && ($list->tokens[$nextidx]->type === Token::TYPE_KEYWORD)
520 144
                && ($list->tokens[$nextidx]->value === 'SELECT')
521
            ) {
522
                /* CREATE TABLE ... AS SELECT */
523 4
                $list->idx = $nextidx;
524 4
                $this->select = new SelectStatement($parser, $list);
525 140
            } elseif ($token->type === Token::TYPE_KEYWORD && $token->keyword === 'LIKE') {
526
                /* CREATE TABLE `new_tbl` LIKE 'orig_tbl' */
527 12
                $list->idx = $nextidx;
528 12
                $this->like = Expression::parse(
529 12
                    $parser,
530 12
                    $list,
531
                    [
532 12
                        'parseField' => 'table',
533
                        'breakOnAlias' => true,
534
                    ]
535
                );
536
                // The 'LIKE' keyword was found, but no table_name was found next to it
537 12
                if ($this->like === null) {
538 12
                    $parser->error('A table name was expected.', $list->tokens[$list->idx]);
539
                }
540
            } else {
541 132
                $this->fields = CreateDefinition::parse($parser, $list);
542 132
                if (empty($this->fields)) {
543 12
                    $parser->error('At least one column definition was expected.', $list->tokens[$list->idx]);
544
                }
545
546 132
                ++$list->idx;
547
548 132
                $this->entityOptions = OptionsArray::parse($parser, $list, static::$TABLE_OPTIONS);
549
550
                /**
551
                 * The field that is being filled (`partitionBy` or
552
                 * `subpartitionBy`).
553
                 *
554
                 * @var string
555
                 */
556 132
                $field = null;
557
558
                /**
559
                 * The number of brackets. `false` means no bracket was found
560
                 * previously. At least one bracket is required to validate the
561
                 * expression.
562
                 *
563
                 * @var int|bool
564
                 */
565 132
                $brackets = false;
566
567
                /*
568
                 * Handles partitions.
569
                 */
570 152
                for (; $list->idx < $list->count; ++$list->idx) {
571
                    /**
572
                     * Token parsed at this moment.
573
                     *
574
                     * @var Token
575
                     */
576 132
                    $token = $list->tokens[$list->idx];
577
578
                    // End of statement.
579 132
                    if ($token->type === Token::TYPE_DELIMITER) {
580 100
                        break;
581
                    }
582
583
                    // Skipping comments.
584 132
                    if ($token->type === Token::TYPE_COMMENT) {
585 4
                        continue;
586
                    }
587
588 132
                    if (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'PARTITION BY')) {
589 20
                        $field = 'partitionBy';
590 20
                        $brackets = false;
591 132
                    } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SUBPARTITION BY')) {
592 16
                        $field = 'subpartitionBy';
593 16
                        $brackets = false;
594 132
                    } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'PARTITIONS')) {
595 8
                        $token = $list->getNextOfType(Token::TYPE_NUMBER);
596 8
                        --$list->idx; // `getNextOfType` also advances one position.
597 8
                        $this->partitionsNum = $token->value;
598 132
                    } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->keyword === 'SUBPARTITIONS')) {
599 8
                        $token = $list->getNextOfType(Token::TYPE_NUMBER);
600 8
                        --$list->idx; // `getNextOfType` also advances one position.
601 8
                        $this->subpartitionsNum = $token->value;
602 132
                    } elseif (! empty($field)) {
603
                        /*
604
                         * Handling the content of `PARTITION BY` and `SUBPARTITION BY`.
605
                         */
606
607
                        // Counting brackets.
608 20
                        if ($token->type === Token::TYPE_OPERATOR) {
609 20
                            if ($token->value === '(') {
610
                                // This is used instead of `++$brackets` because,
611
                                // initially, `$brackets` is `false` cannot be
612
                                // incremented.
613 20
                                $brackets += 1;
614 20
                            } elseif ($token->value === ')') {
615 20
                                --$brackets;
616
                            }
617
                        }
618
619
                        // Building the expression used for partitioning.
620 20
                        $this->$field .= $token->type === Token::TYPE_WHITESPACE ? ' ' : $token->token;
621
622
                        // Last bracket was read, the expression ended.
623
                        // Comparing with `0` and not `false`, because `false` means
624
                        // that no bracket was found and at least one must is
625
                        // required.
626 20
                        if ($brackets === 0) {
627 20
                            $this->$field = trim($this->$field);
628 20
                            $field = null;
629
                        }
630 132
                    } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
631 32
                        if (! empty($this->partitionBy)) {
632 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...s\PartitionDefinition[] 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...
633 20
                                $parser,
634 20
                                $list,
635 20
                                ['type' => 'PhpMyAdmin\\SqlParser\\Components\\PartitionDefinition']
636
                            );
637
                        }
638
639 32
                        break;
640
                    }
641
                }
642
            }
643 88
        } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) {
644 44
            $this->parameters = ParameterDefinition::parse($parser, $list);
645 44
            if ($this->options->has('FUNCTION')) {
646 24
                $prevToken = $token;
647 24
                $token = $list->getNextOfType(Token::TYPE_KEYWORD);
648 24
                if ($token === null || $token->keyword !== 'RETURNS') {
649 12
                    $parser->error('A "RETURNS" keyword was expected.', $token ?? $prevToken);
650
                } else {
651 12
                    ++$list->idx;
652 12
                    $this->return = DataType::parse($parser, $list);
653
                }
654
            }
655
656 44
            ++$list->idx;
657
658 44
            $this->entityOptions = OptionsArray::parse($parser, $list, static::$FUNC_OPTIONS);
659 44
            ++$list->idx;
660
661 44
            for (; $list->idx < $list->count; ++$list->idx) {
662 36
                $token = $list->tokens[$list->idx];
663 36
                $this->body[] = $token;
664
            }
665 44
        } elseif ($this->options->has('VIEW')) {
666
            /** @var Token $token */
667 24
            $token = $list->getNext(); // Skipping whitespaces and comments.
668
669
            // Parsing columns list.
670 24
            if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
671 8
                --$list->idx; // getNext() also goes forward one field.
672 8
                $this->fields = ArrayObj::parse($parser, $list);
673 8
                ++$list->idx; // Skipping last token from the array.
674 8
                $list->getNext();
675
            }
676
677
            // Parsing the SELECT expression with and without the `AS` keyword
678 24
            if ($token->type === Token::TYPE_KEYWORD && $token->keyword === 'SELECT') {
679
                $this->select = new SelectStatement($parser, $list);
680
            } elseif (
681 24
                $token->type === Token::TYPE_KEYWORD
682 24
                && $token->keyword === 'AS'
683 24
                && $list->tokens[$nextidx]->type === Token::TYPE_KEYWORD
684 24
                && $list->tokens[$nextidx]->value === 'SELECT'
685
            ) {
686 16
                $list->idx = $nextidx;
687 16
                $this->select = new SelectStatement($parser, $list);
688
            } else {
689 24
                for (; $list->idx < $list->count; ++$list->idx) {
690 8
                    $token = $list->tokens[$list->idx];
691 8
                    if ($token->type === Token::TYPE_DELIMITER) {
692 8
                        break;
693
                    }
694
695 8
                    $this->body[] = $token;
696
                }
697
            }
698 20
        } elseif ($this->options->has('TRIGGER')) {
699
            // Parsing the time and the event.
700 4
            $this->entityOptions = OptionsArray::parse($parser, $list, static::$TRIGGER_OPTIONS);
701 4
            ++$list->idx;
702
703 4
            $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'ON');
704 4
            ++$list->idx; // Skipping `ON`.
705
706
            // Parsing the name of the table.
707 4
            $this->table = Expression::parse(
708 4
                $parser,
709 4
                $list,
710
                [
711 4
                    'parseField' => 'table',
712
                    'breakOnAlias' => true,
713
                ]
714
            );
715 4
            ++$list->idx;
716
717 4
            $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'FOR EACH ROW');
718 4
            ++$list->idx; // Skipping `FOR EACH ROW`.
719
720 4
            for (; $list->idx < $list->count; ++$list->idx) {
721 4
                $token = $list->tokens[$list->idx];
722 4
                $this->body[] = $token;
723
            }
724
        } else {
725 16
            for (; $list->idx < $list->count; ++$list->idx) {
726 16
                $token = $list->tokens[$list->idx];
727 16
                if ($token->type === Token::TYPE_DELIMITER) {
728 16
                    break;
729
                }
730
731 4
                $this->body[] = $token;
732
            }
733
        }
734 260
    }
735
}
736