Passed
Pull Request — master (#535)
by
unknown
02:55
created

SetOperations   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 103
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 41
c 0
b 0
f 0
dl 0
loc 103
rs 10
ccs 43
cts 43
cp 1
wmc 16

2 Methods

Rating   Name   Duplication   Size   Complexity  
A buildAll() 0 3 1
C parse() 0 88 15
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser\Components\Parsers;
6
7
use PhpMyAdmin\SqlParser\Components\Expression;
8
use PhpMyAdmin\SqlParser\Components\SetOperation;
9
use PhpMyAdmin\SqlParser\Parseable;
10
use PhpMyAdmin\SqlParser\Parser;
11
use PhpMyAdmin\SqlParser\Token;
12
use PhpMyAdmin\SqlParser\TokensList;
13
use PhpMyAdmin\SqlParser\TokenType;
14
15
use function implode;
16
use function in_array;
17
use function trim;
18
19
/**
20
 * `SET` keyword parser.
21
 */
22
final class SetOperations implements Parseable
23
{
24
    /**
25
     * @param Parser               $parser  the parser that serves as context
26
     * @param TokensList           $list    the list of tokens that are being parsed
27
     * @param array<string, mixed> $options parameters for parsing
28
     *
29
     * @return SetOperation[]
30
     */
31 120
    public static function parse(Parser $parser, TokensList $list, array $options = []): array
32
    {
33 120
        $ret = [];
34
35 120
        $expr = new SetOperation();
36
37
        /**
38
         * The state of the parser.
39
         *
40
         * Below are the states of the parser.
41
         *
42
         *      0 ---------------------[ col_name ]--------------------> 0
43
         *      0 ---------------------[ = or := ]---------------------> 1
44
         *      1 -----------------------[ value ]---------------------> 1
45
         *      1 ------------------------[ , ]------------------------> 0
46
         *
47
         * @var int
48
         */
49 120
        $state = 0;
50
51
        /**
52
         * Token when the parser has seen the latest comma
53
         *
54
         * @var Token
55
         */
56 120
        $commaLastSeenAt = null;
57
58 120
        for (; $list->idx < $list->count; ++$list->idx) {
59
            /**
60
             * Token parsed at this moment.
61
             */
62 120
            $token = $list->tokens[$list->idx];
63
64
            // End of statement.
65 120
            if ($token->type === TokenType::Delimiter) {
66 90
                break;
67
            }
68
69
            // Skipping whitespaces and comments.
70 100
            if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) {
71 90
                continue;
72
            }
73
74
            // No keyword is expected.
75
            if (
76 100
                ($token->type === TokenType::Keyword)
77 100
                && ($token->flags & Token::FLAG_KEYWORD_RESERVED)
78 100
                && ($state === 0)
79
            ) {
80 32
                break;
81
            }
82
83 100
            if ($state === 0) {
84 100
                if (in_array($token->token, ['=', ':='], true)) {
85 100
                    $state = 1;
86 98
                } elseif ($token->value !== ',') {
87 98
                    $expr->column .= $token->token;
88 24
                } elseif ($token->value === ',') {
89 62
                    $commaLastSeenAt = $token;
90
                }
91 100
            } elseif ($state === 1) {
92 100
                $tmp = Expression::parse(
93 100
                    $parser,
94 100
                    $list,
95 100
                    ['breakOnAlias' => true],
96 100
                );
97 100
                if ($tmp === null) {
98 2
                    $parser->error('Missing expression.', $token);
99 2
                    break;
100
                }
101
102 98
                $expr->column = trim($expr->column);
103 98
                $expr->value = $tmp->expr;
104 98
                $ret[] = $expr;
105 98
                $expr = new SetOperation();
106 98
                $state = 0;
107 98
                $commaLastSeenAt = null;
108
            }
109
        }
110
111 120
        --$list->idx;
112
113
        // We saw a comma, but didn't see a column-value pair after it
114 120
        if ($commaLastSeenAt !== null) {
0 ignored issues
show
introduced by
The condition $commaLastSeenAt !== null is always false.
Loading history...
115 2
            $parser->error('Unexpected token.', $commaLastSeenAt);
116
        }
117
118 120
        return $ret;
119
    }
120
121
    /** @param SetOperation[] $component the component to be built */
122 38
    public static function buildAll(array $component): string
123
    {
124 38
        return implode(', ', $component);
125
    }
126
}
127