Completed
Push — master ( 3c77d0...8159f2 )
by Michal
182:48 queued 117:53
created

CreateStatement   D

Complexity

Total Complexity 75

Size/Duplication

Total Lines 607
Duplicated Lines 3.62 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 100%

Importance

Changes 14
Bugs 5 Features 3
Metric Value
c 14
b 5
f 3
dl 22
loc 607
ccs 225
cts 225
cp 1
rs 4.9978
wmc 75
lcom 1
cbo 12

2 Methods

Rating   Name   Duplication   Size   Complexity  
D build() 0 81 20
F parse() 22 277 55

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
/**
4
 * `CREATE` statement.
5
 *
6
 * @package    SqlParser
7
 * @subpackage Statements
8
 */
9
namespace SqlParser\Statements;
10
11
use SqlParser\Parser;
12
use SqlParser\Statement;
13
use SqlParser\Token;
14
use SqlParser\Context;
15
use SqlParser\TokensList;
16
use SqlParser\Components\ArrayObj;
17
use SqlParser\Components\DataType;
18
use SqlParser\Components\CreateDefinition;
19
use SqlParser\Components\PartitionDefinition;
20
use SqlParser\Components\Expression;
21
use SqlParser\Components\OptionsArray;
22
use SqlParser\Components\ParameterDefinition;
23
use SqlParser\Statements\SelectStatement;
24
25
/**
26
 * `CREATE` statement.
27
 *
28
 * @category   Statements
29
 * @package    SqlParser
30
 * @subpackage Statements
31
 * @author     Dan Ungureanu <[email protected]>
32
 * @license    http://opensource.org/licenses/GPL-2.0 GNU Public License
33
 */
34
class CreateStatement extends Statement
35
{
36
37
    /**
38
     * Options for `CREATE` statements.
39
     *
40
     * @var array
41
     */
42
    public static $OPTIONS = array(
43
44
        // CREATE TABLE
45
        'TEMPORARY'                     => 1,
46
47
        // CREATE VIEW
48
        'OR REPLACE'                    => array(2, 'var='),
49
        'ALGORITHM'                     => array(3, 'var='),
50
        // `DEFINER` is also used for `CREATE FUNCTION / PROCEDURE`
51
        'DEFINER'                       => array(4, 'var='),
52
        'SQL SECURITY'                  => array(5, 'var'),
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
69
        // CREATE TABLE
70
        'IF NOT EXISTS'                 => 7,
71
    );
72
73
    /**
74
     * All database options.
75
     *
76
     * @var array
77
     */
78
    public static $DB_OPTIONS = array(
79
        'CHARACTER SET'                 => array(1, 'var='),
80
        'CHARSET'                       => array(1, 'var='),
81
        'DEFAULT CHARACTER SET'         => array(1, 'var='),
82
        'DEFAULT CHARSET'               => array(1, 'var='),
83
        'DEFAULT COLLATE'               => array(2, 'var='),
84
        'COLLATE'                       => array(2, 'var='),
85
    );
86
87
    /**
88
     * All table options.
89
     *
90
     * @var array
91
     */
92
    public static $TABLE_OPTIONS = array(
93
        'ENGINE'                        => array(1, 'var='),
94
        'AUTO_INCREMENT'                => array(2, 'var='),
95
        'AVG_ROW_LENGTH'                => array(3, 'var'),
96
        'CHARACTER SET'                 => array(4, 'var='),
97
        'CHARSET'                       => array(4, 'var='),
98
        'DEFAULT CHARACTER SET'         => array(4, 'var='),
99
        'DEFAULT CHARSET'               => array(4, 'var='),
100
        'CHECKSUM'                      => array(5, 'var'),
101
        'DEFAULT COLLATE'               => array(6, 'var='),
102
        'COLLATE'                       => array(6, 'var='),
103
        'COMMENT'                       => array(7, 'var='),
104
        'CONNECTION'                    => array(8, 'var'),
105
        'DATA DIRECTORY'                => array(9, 'var'),
106
        'DELAY_KEY_WRITE'               => array(10, 'var'),
107
        'INDEX DIRECTORY'               => array(11, 'var'),
108
        'INSERT_METHOD'                 => array(12, 'var'),
109
        'KEY_BLOCK_SIZE'                => array(13, 'var'),
110
        'MAX_ROWS'                      => array(14, 'var'),
111
        'MIN_ROWS'                      => array(15, 'var'),
112
        'PACK_KEYS'                     => array(16, 'var'),
113
        'PASSWORD'                      => array(17, 'var'),
114
        'ROW_FORMAT'                    => array(18, 'var'),
115
        'TABLESPACE'                    => array(19, 'var'),
116
        'STORAGE'                       => array(20, 'var'),
117
        'UNION'                         => array(21, 'var'),
118
    );
119
120
    /**
121
     * All function options.
122
     *
123
     * @var array
124
     */
125
    public static $FUNC_OPTIONS = array(
126
        'COMMENT'                       => array(1, 'var='),
127
        'LANGUAGE SQL'                  => 2,
128
        'DETERMINISTIC'                 => 3,
129
        'NOT DETERMINISTIC'             => 3,
130
        'CONTAINS SQL'                  => 4,
131
        'NO SQL'                        => 4,
132
        'READS SQL DATA'                => 4,
133
        'MODIFIES SQL DATA'             => 4,
134
        'SQL SECURITY DEFINER'          => array(5, 'var'),
135
    );
136
137
    /**
138
     * All trigger options.
139
     *
140
     * @var array
141
     */
142
    public static $TRIGGER_OPTIONS = array(
143
        'BEFORE'                        => 1,
144
        'AFTER'                         => 1,
145
        'INSERT'                        => 2,
146
        'UPDATE'                        => 2,
147
        'DELETE'                        => 2,
148
    );
149
150
    /**
151
     * The name of the entity that is created.
152
     *
153
     * Used by all `CREATE` statements.
154
     *
155
     * @var Expression
156
     */
157
    public $name;
158
159
    /**
160
     * The options of the entity (table, procedure, function, etc.).
161
     *
162
     * Used by `CREATE TABLE`, `CREATE FUNCTION` and `CREATE PROCEDURE`.
163
     *
164
     * @var OptionsArray
165
     *
166
     * @see static::$TABLE_OPTIONS
167
     * @see static::$FUNC_OPTIONS
168
     * @see static::$TRIGGER_OPTIONS
169
     */
170
    public $entityOptions;
171
172
    /**
173
     * If `CREATE TABLE`, a list of columns and keys.
174
     * If `CREATE VIEW`, a list of columns.
175
     *
176
     * Used by `CREATE TABLE` and `CREATE VIEW`.
177
     *
178
     * @var CreateDefinition[]|ArrayObj
179
     */
180
    public $fields;
181
182
    /**
183
     * If `CREATE TABLE ... SELECT`
184
     *
185
     * Used by `CREATE TABLE`
186
     *
187
     * @var SelectStatement
188
     */
189
    public $select;
190
191
    /**
192
     * If `CREATE TABLE ... LIKE`
193
     *
194
     * Used by `CREATE TABLE`
195
     *
196
     * @var Expression
197
     */
198
    public $like;
199
200
    /**
201
     * Expression used for partitioning.
202
     *
203
     * @var string
204
     */
205
    public $partitionBy;
206
207
    /**
208
     * The number of partitions.
209
     *
210
     * @var int
211
     */
212
    public $partitionsNum;
213
214
    /**
215
     * Expression used for subpartitioning.
216
     *
217
     * @var string
218
     */
219
    public $subpartitionBy;
220
221
    /**
222
     * The number of subpartitions.
223
     *
224
     * @var int
225
     */
226
    public $subpartitionsNum;
227
228
    /**
229
     * The partition of the new table.
230
     *
231
     * @var PartitionDefinition[]
232
     */
233
    public $partitions;
234
235
    /**
236
     * If `CREATE TRIGGER` the name of the table.
237
     *
238
     * Used by `CREATE TRIGGER`.
239
     *
240
     * @var Expression
241
     */
242
    public $table;
243
244
    /**
245
     * The return data type of this routine.
246
     *
247
     * Used by `CREATE FUNCTION`.
248
     *
249
     * @var DataType
250
     */
251
    public $return;
252
253
    /**
254
     * The parameters of this routine.
255
     *
256
     * Used by `CREATE FUNCTION` and `CREATE PROCEDURE`.
257
     *
258
     * @var ParameterDefinition[]
259
     */
260
    public $parameters;
261
262
    /**
263
     * The body of this function or procedure. For views, it is the select
264
     * statement that gets the
265 10
     *
266
     * Used by `CREATE FUNCTION`, `CREATE PROCEDURE` and `CREATE VIEW`.
267 10
     *
268 10
     * @var Token[]|string
269 5
     */
270 4
    public $body = array();
271 5
272 1
    /**
273 1
     * @return string
274 5
     */
275 10
    public function build()
276
    {
277 1
        $fields = '';
278 1
        if (!empty($this->fields)) {
279 1
            if (is_array($this->fields)) {
280 9
                $fields = CreateDefinition::build($this->fields) . ' ';
281
            } elseif ($this->fields instanceof ArrayObj) {
282 1
                $fields = ArrayObj::build($this->fields);
283 1
            }
284 1
        }
285 8
        if ($this->options->has('DATABASE')) {
286 4
            return 'CREATE '
287
                . OptionsArray::build($this->options) . ' '
288 4
                . Expression::build($this->name) . ' '
289 1
                . OptionsArray::build($this->entityOptions);
290 1
        } elseif ($this->options->has('TABLE') && !is_null($this->select)) {
291 4
            return 'CREATE '
292 1
                . OptionsArray::build($this->options) . ' '
293 1
                . Expression::build($this->name) . ' '
294 4
                . $this->select->build();
295 1
        } elseif ($this->options->has('TABLE') && !is_null($this->like)) {
296 1
            return 'CREATE '
297 4
                . OptionsArray::build($this->options) . ' '
298 1
                . Expression::build($this->name) . ' LIKE '
299 1
                . Expression::build($this->like);
300 4
        } elseif ($this->options->has('TABLE')) {
301 1
            $partition = '';
302 1
303
            if (!empty($this->partitionBy)) {
304
                $partition .= "\nPARTITION BY " . $this->partitionBy;
305 4
            }
306 4
            if (!empty($this->partitionsNum)) {
307 4
                $partition .= "\nPARTITIONS " . $this->partitionsNum;
308 4
            }
309 4
            if (!empty($this->subpartitionBy)) {
310 4
                $partition .= "\nSUBPARTITION BY " . $this->subpartitionBy;
311
            }
312 1
            if (!empty($this->subpartitionsNum)) {
313 1
                $partition .= "\nSUBPARTITIONS " . $this->subpartitionsNum;
314 1
            }
315 1
            if (!empty($this->partitions)) {
316 3
                $partition .= "\n" . PartitionDefinition::build($this->partitions);
317
            }
318 1
319 1
            return 'CREATE '
320 1
                . OptionsArray::build($this->options) . ' '
321 1
                . Expression::build($this->name) . ' '
322 1
                . $fields
323 2
                . OptionsArray::build($this->entityOptions)
324 2
                . $partition;
325 2
        } elseif ($this->options->has('VIEW')) {
326 1
            return 'CREATE '
327 1
                . OptionsArray::build($this->options) . ' '
328 1
                . Expression::build($this->name) . ' '
329 1
                . $fields . ' AS ' . TokensList::build($this->body) . ' '
330
                . OptionsArray::build($this->entityOptions);
331 1
        } elseif ($this->options->has('TRIGGER')) {
332 1
            return 'CREATE '
333 1
                . OptionsArray::build($this->options) . ' '
334 1
                . Expression::build($this->name) . ' '
335
                . OptionsArray::build($this->entityOptions) . ' '
336
                . 'ON ' . Expression::build($this->table) . ' '
337 1
                . 'FOR EACH ROW ' . TokensList::build($this->body);
338 1
        } elseif (($this->options->has('PROCEDURE'))
339 1
            || ($this->options->has('FUNCTION'))
340
        ) {
341
            $tmp = '';
342
            if ($this->options->has('FUNCTION')) {
343
                $tmp = 'RETURNS ' . DataType::build($this->return);
344
            }
345
            return 'CREATE '
346
                . OptionsArray::build($this->options) . ' '
347
                . Expression::build($this->name) . ' '
348 42
                . ParameterDefinition::build($this->parameters) . ' '
349
                . $tmp . ' ' . TokensList::build($this->body);
350 42
        }
351
        return 'CREATE '
352
            . OptionsArray::build($this->options) . ' '
353 42
            . Expression::build($this->name) . ' '
354 42
            . TokensList::build($this->body);
355
    }
356
357 42
    /**
358 42
     * @param Parser     $parser The instance that requests parsing.
359 42
     * @param TokensList $list   The list of tokens to be parsed.
360
     *
361 42
     * @return void
362 42
     */
363
    public function parse(Parser $parser, TokensList $list)
364 42
    {
365
        ++$list->idx; // Skipping `CREATE`.
366 42
367 1
        // Parsing options.
368 1
        $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
369 1
        ++$list->idx; // Skipping last option.
370 1
371 1
        // Parsing the field name.
372 41
        $this->name = Expression::parse(
373
            $parser,
374
            $list,
375
            array(
376
                'parseField' => 'table',
377
                'breakOnAlias' => true,
378
            )
379
        );
380 42
381 42
        if ((!isset($this->name)) || ($this->name === '')) {
382 42
            $parser->error(
383 22
                __('The name of the entity was expected.'),
384 22
                $list->tokens[$list->idx]
385
            );
386 42
        } else {
387 1
            ++$list->idx; // Skipping field.
388 1
        }
389 1
390
        /**
391 1
         * Token parsed at this moment.
392 42
         *
393
         * @var Token $token
394 2
         */
395 2
        $token = $list->tokens[$list->idx];
396 39
        $nextidx = $list->idx + 1;
397 39
        while ($nextidx < $list->count && $list->tokens[$nextidx]->type == Token::TYPE_WHITESPACE) {
398 39
            $nextidx++;
399 39
        }
400
401 1
        if ($this->options->has('DATABASE')) {
402 1
            $this->entityOptions = OptionsArray::parse(
403 39
                $parser,
404 20
                $list,
405 20
                static::$DB_OPTIONS
406 1
            );
407 1
        } elseif ($this->options->has('TABLE')
408 1
            && ($token->type == Token::TYPE_KEYWORD)
409 1
            && ($token->value == 'SELECT')
410 1
        ) {
411 20
            /* CREATE TABLE ... SELECT */
412
            $this->select = new SelectStatement($parser, $list);
413 20
        } elseif ($this->options->has('TABLE')
414 20
            && ($token->type == Token::TYPE_KEYWORD) && ($token->value == 'AS')
415 20
            && ($list->tokens[$nextidx]->type == Token::TYPE_KEYWORD)
416
            && ($list->tokens[$nextidx]->value == 'SELECT')
417 20
        ) {
418
            /* CREATE TABLE ... AS SELECT */
419
            $list->idx = $nextidx;
420
            $this->select = new SelectStatement($parser, $list);
421
        } elseif ($this->options->has('TABLE')
422
            && $token->type == Token::TYPE_KEYWORD
423
            && $token->value == 'LIKE'
424
        ) {
425 20
            /* CREATE TABLE `new_tbl` LIKE 'orig_tbl' */
426
            $list->idx = $nextidx;
427
            $this->like = $this->table = Expression::parse(
428
                $parser,
429
                $list,
430
                array(
431
                    'parseField' => 'table',
432
                    'breakOnAlias' => true,
433
                )
434 20
            );
435
            // The 'LIKE' keyword was found, but no table_name was found next to it
436
            if ($this->like == null) {
437
                $parser->error(
438
                    __('A table name was expected.'),
439 20
                    $list->tokens[$list->idx]
440
                );
441
            }
442
        } elseif ($this->options->has('TABLE')) {
443
            $this->fields = CreateDefinition::parse($parser, $list);
444
            if (empty($this->fields)) {
445 20
                $parser->error(
446
                    __('At least one column definition was expected.'),
447
                    $list->tokens[$list->idx]
448 20
                );
449 17
            }
450
            ++$list->idx;
451
452
            $this->entityOptions = OptionsArray::parse(
453 20
                $parser,
454 1
                $list,
455
                static::$TABLE_OPTIONS
456
            );
457 20
458 2
            /**
459 2
             * The field that is being filled (`partitionBy` or
460 20
             * `subpartitionBy`).
461 2
             *
462 2
             * @var string $field
463 20
             */
464 2
            $field = null;
465 2
466 2
            /**
467 20
             * The number of brackets. `false` means no bracket was found
468 2
             * previously. At least one bracket is required to validate the
469 2
             * expression.
470 2
             *
471 20
             * @var int|bool $brackets
472
             */
473
            $brackets = false;
474
475
            /*
476
             * Handles partitions.
477 2
             */
478
            for (; $list->idx < $list->count; ++$list->idx) {
479
                /**
480
                 * Token parsed at this moment.
481 2
                 *
482 2
                 * @var Token $token
483 2
                 */
484 2
                $token = $list->tokens[$list->idx];
485
486
                // End of statement.
487 2
                if ($token->type === Token::TYPE_DELIMITER) {
488
                    break;
489
                }
490
491
                // Skipping comments.
492
                if ($token->type === Token::TYPE_COMMENT) {
493 2
                    continue;
494 2
                }
495 2
496 2
                if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'PARTITION BY')) {
497 20
                    $field = 'partitionBy';
498 3
                    $brackets = false;
499 2
                } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITION BY')) {
500 2
                    $field = 'subpartitionBy';
501 2
                    $brackets = false;
502
                } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'PARTITIONS')) {
503
                    $token = $list->getNextOfType(Token::TYPE_NUMBER);
504 2
                    --$list->idx; // `getNextOfType` also advances one position.
505 2
                    $this->partitionsNum = $token->value;
0 ignored issues
show
Documentation Bug introduced by
The property $partitionsNum was declared of type integer, but $token->value is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
506 2
                } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITIONS')) {
507 3
                    $token = $list->getNextOfType(Token::TYPE_NUMBER);
508
                    --$list->idx; // `getNextOfType` also advances one position.
509 20
                    $this->subpartitionsNum = $token->value;
0 ignored issues
show
Documentation Bug introduced by
The property $subpartitionsNum was declared of type integer, but $token->value is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
510 38
                } elseif (!empty($field)) {
511 13
                    /*
512 18
                     * Handling the content of `PARTITION BY` and `SUBPARTITION BY`.
513 10
                     */
514 10
515 5
                    // Counting brackets.
516 5 View Code Duplication
                    if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
517 2
                        // This is used instead of `++$brackets` because,
518 2
                        // initially, `$brackets` is `false` cannot be
519
                        // incremented.
520 2
                        $brackets = $brackets + 1;
521 2
                    } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ')')) {
522 3
                        --$brackets;
523 3
                    }
524 3
525
                    // Building the expression used for partitioning.
526 3
                    $this->$field .= ($token->type === Token::TYPE_WHITESPACE) ? ' ' : $token->token;
527
528 5
                    // Last bracket was read, the expression ended.
529 10
                    // Comparing with `0` and not `false`, because `false` means
530
                    // that no bracket was found and at least one must is
531 10
                    // required.
532 10
                    if ($brackets === 0) {
533 10
                        $this->$field = trim($this->$field);
534
                        $field = null;
535 10
                    }
536 10
                } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
537
                    if (!empty($this->partitionBy)) {
538 10
                        $this->partitions = ArrayObj::parse(
0 ignored issues
show
Documentation Bug introduced by
It seems like \SqlParser\Components\Ar...\PartitionDefinition')) can also be of type object<SqlParser\Components\ArrayObj>. However, the property $partitions is declared as type array<integer,object<Sql...s\PartitionDefinition>>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
539 9
                            $parser,
540 9
                            $list,
541 9
                            array(
542 18
                                'type' => 'SqlParser\\Components\\PartitionDefinition'
543 3
                            )
544
                        );
545
                    }
546 3
                    break;
547 2
                }
548 2
            }
549 2
        } elseif (($this->options->has('PROCEDURE'))
550 2
            || ($this->options->has('FUNCTION'))
551 2
        ) {
552
            $this->parameters = ParameterDefinition::parse($parser, $list);
553
            if ($this->options->has('FUNCTION')) {
554 3
                $token = $list->getNextOfType(Token::TYPE_KEYWORD);
555 3
                if ($token->value !== 'RETURNS') {
556 3
                    $parser->error(
557 3
                        __('A "RETURNS" keyword was expected.'),
558
                        $token
559 3
                    );
560 3
                } else {
561 8
                    ++$list->idx;
562
                    $this->return = DataType::parse(
563 1
                        $parser,
564 1
                        $list
565 1
                    );
566
                }
567 1
            }
568 1
            ++$list->idx;
569
570 1
            $this->entityOptions = OptionsArray::parse(
571 1
                $parser,
572
                $list,
573
                static::$FUNC_OPTIONS
574 1
            );
575 1
            ++$list->idx;
576 1
577
            for (; $list->idx < $list->count; ++$list->idx) {
578 1
                $token = $list->tokens[$list->idx];
579 1
                $this->body[] = $token;
580
            }
581 1
        } elseif ($this->options->has('VIEW')) {
582 1
            $token = $list->getNext(); // Skipping whitespaces and comments.
583
584 1
            // Parsing columns list.
585 1
            if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
586
                --$list->idx; // getNext() also goes forward one field.
587 1
                $this->fields = ArrayObj::parse($parser, $list);
588 1
                ++$list->idx; // Skipping last token from the array.
589 1
                $list->getNext();
590 1
            }
591 1
592 4
            // Parsing the `AS` keyword.
593 4 View Code Duplication
            for (; $list->idx < $list->count; ++$list->idx) {
594 4
                $token = $list->tokens[$list->idx];
595 4
                if ($token->type === Token::TYPE_DELIMITER) {
596
                    break;
597 1
                }
598 1
                $this->body[] = $token;
599
            }
600 42
        } elseif ($this->options->has('TRIGGER')) {
601
            // Parsing the time and the event.
602
            $this->entityOptions = OptionsArray::parse(
603
                $parser,
604
                $list,
605
                static::$TRIGGER_OPTIONS
606
            );
607
            ++$list->idx;
608
609
            $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'ON');
610
            ++$list->idx; // Skipping `ON`.
611
612
            // Parsing the name of the table.
613
            $this->table = Expression::parse(
614
                $parser,
615
                $list,
616
                array(
617
                    'parseField' => 'table',
618
                    'breakOnAlias' => true,
619
                )
620
            );
621
            ++$list->idx;
622
623
            $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'FOR EACH ROW');
624
            ++$list->idx; // Skipping `FOR EACH ROW`.
625
626
            for (; $list->idx < $list->count; ++$list->idx) {
627
                $token = $list->tokens[$list->idx];
628
                $this->body[] = $token;
629
            }
630
        } else {
631 View Code Duplication
            for (; $list->idx < $list->count; ++$list->idx) {
632
                $token = $list->tokens[$list->idx];
633
                if ($token->type === Token::TYPE_DELIMITER) {
634
                    break;
635
                }
636
                $this->body[] = $token;
637
            }
638
        }
639
    }
640
}
641