Completed
Pull Request — master (#76)
by Deven
65:45
created

InsertStatement::build()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 20
Code Lines 12

Duplication

Lines 6
Ratio 30 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 9
eloc 12
nc 8
nop 0
dl 6
loc 20
ccs 0
cts 0
cp 0
crap 90
rs 7.756
c 2
b 0
f 0
1
<?php
2
3
/**
4
 * `INSERT` statement.
5
 *
6
 * @package    SqlParser
7
 * @subpackage Statements
8
 */
9
namespace SqlParser\Statements;
10
11
use SqlParser\Parser;
12
use SqlParser\Token;
13
use SqlParser\TokensList;
14
use SqlParser\Statement;
15
use SqlParser\Statements\SelectStatement;
16
use SqlParser\Components\IntoKeyword;
17
use SqlParser\Components\Array2d;
18
use SqlParser\Components\ArrayObj;
19
use SqlParser\Components\OptionsArray;
20
use SqlParser\Components\SetOperation;
21
22
/**
23
 * `INSERT` statement.
24
 *
25
 * INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
26
 *     [INTO] tbl_name
27
 *     [PARTITION (partition_name,...)]
28
 *     [(col_name,...)]
29
 *     {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
30
 *     [ ON DUPLICATE KEY UPDATE
31
 *       col_name=expr
32
 *         [, col_name=expr] ... ]
33
 *
34
 * or
35
 *
36
 * INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
37
 *     [INTO] tbl_name
38
 *     [PARTITION (partition_name,...)]
39
 *     SET col_name={expr | DEFAULT}, ...
40
 *     [ ON DUPLICATE KEY UPDATE
41
 *       col_name=expr
42
 *         [, col_name=expr] ... ]
43
 *
44
 * or
45
 *
46
 * INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
47
 *     [INTO] tbl_name
48
 *     [PARTITION (partition_name,...)]
49
 *     [(col_name,...)]
50
 *     SELECT ...
51
 *     [ ON DUPLICATE KEY UPDATE
52
 *       col_name=expr
53
 *         [, col_name=expr] ... ]
54
 *
55
 * @category   Statements
56
 * @package    SqlParser
57
 * @subpackage Statements
58
 * @author     Dan Ungureanu <[email protected]>
59
 * @license    http://opensource.org/licenses/GPL-2.0 GNU Public License
60
 */
61
class InsertStatement extends Statement
62
{
63
64
    /**
65
     * Options for `INSERT` statements.
66
     *
67
     * @var array
68
     */
69
    public static $OPTIONS = array(
70
        'LOW_PRIORITY'                  => 1,
71
        'DELAYED'                       => 2,
72
        'HIGH_PRIORITY'                 => 3,
73
        'IGNORE'                        => 4,
74
    );
75
76
    /**
77
     * Tables used as target for this statement.
78
     *
79
     * @var IntoKeyword
80
     */
81
    public $into;
82
83
    /**
84
     * Values to be inserted.
85
     *
86
     * @var ArrayObj[]
87 1
     */
88
    public $values;
89 1
90 1
    /**
91 1
     * If SET clause is present
92
     * holds the SetOperation
93
     *
94
     * @var SetOperation[]
95
     */
96
    public $set;
97
98
    /**
99
     * If SELECT clause is present
100
     * holds the SelectStatement
101
     *
102
     * @var SelectStatement
103
     */
104
    public $select;
105
106
    /**
107
     * If ON DUPLICATE KEY UPDATE clause is present
108
     * holds the SetOperation
109
     *
110
     * @var SetOperation[]
111
     */
112
    public $onDuplicateSet;
113
114
    /**
115
     * @return string
116
     */
117
    public function build()
118
    {
119
        $ret = 'INSERT ' . $this->options
120
            . ' INTO ' . $this->into;
121
122
        if ($this->values != NULL && count($this->values) > 0) {
123
            $ret .= ' VALUES ' . ArrayObj::build($this->values);
124 View Code Duplication
        } elseif ($this->set != NULL && count($this->set) > 0) {
125
            $ret .= ' SET ' . SetOperation::build($this->set);
126
        } elseif ($this->select != NULL && count($this->select) > 0) {
127
            $ret .= ' ' . $this->select->build();
128
        }
129
130 View Code Duplication
        if ($this->onDuplicateSet != NULL && count($this->onDuplicateSet) > 0) {
131
            $ret .= ' ON DUPLICATE KEY UPDATE ' . SetOperation::build($this->onDuplicateSet);
132
        }
133
134
        return $ret;
135
136
    }
137
138
139
    /**
140
     * @param Parser     $parser The instance that requests parsing.
141
     * @param TokensList $list   The list of tokens to be parsed.
142
     *
143
     * @return void
144
     */
145
    public function parse(Parser $parser, TokensList $list)
146
    {
147
        ++$list->idx; // Skipping `INSERT`.
148
149
        // parse any options if provided
150
        $this->options = OptionsArray::parse(
151
            $parser,
152
            $list,
153
            static::$OPTIONS
154
        );
155
        ++$list->idx;
156
157
        $token = $list->tokens[$list->idx];
0 ignored issues
show
Unused Code introduced by
$token is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
158
159
        /**
160
         * The state of the parser.
161
         *
162
         * Below are the states of the parser.
163
         *
164
         *      0 ---------------------------------[ INTO ]----------------------------------> 1
165
         *
166
         *      1 -------------------------[ VALUES/VALUE/SET/SELECT ]-----------------------> 2
167
         *
168
         *      2 -------------------------[ ON DUPLICATE KEY UPDATE ]-----------------------> 3
169
         *
170
         * @var int $state
171
         */
172
        $state = 0;
173
174
        /**
175
         * For keeping track of semi-states on encountering
176
         * ON DUPLICATE KEY UPDATE ...
177
         *
178
         */
179
        $miniState = 0;
180
181
        for (; $list->idx < $list->count; ++$list->idx) {
182
            /**
183
             * Token parsed at this moment.
184
             *
185
             * @var Token $token
186
             */
187
            $token = $list->tokens[$list->idx];
188
189
            // End of statement.
190
            if ($token->type === Token::TYPE_DELIMITER) {
191
                break;
192
            }
193
194
            // Skipping whitespaces and comments.
195
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
196
                continue;
197
            }
198
199
            if ($state === 0) {
200 View Code Duplication
                if ($token->type === Token::TYPE_KEYWORD
201
                    && $token->value !== 'INTO'
202
                ) {
203
                    $parser->error(__('Unexpected keyword.'), $token);
204
                    break;
205
                } else {
206
                    ++$list->idx;
207
                    $this->into = IntoKeyword::parse($parser, $list);
208
                }
209
210
                $state = 1;
211
            } elseif ($state === 1) {
212
                if ($token->type === Token::TYPE_KEYWORD) {
213
                    if ($token->value === 'VALUE'
214
                        || $token->value === 'VALUES'
215
                    ) {
216
                        ++$list->idx; // skip VALUES
217
218
                        $this->values = Array2d::parse($parser, $list);
219
                    } elseif ($token->value === 'SET') {
220
                        ++$list->idx; // skip SET
221
222
                        $this->set = SetOperation::parse($parser, $list);
223
                    } elseif ($token->value === 'SELECT') {
224
                        $this->select = new SelectStatement($parser, $list);
225
                    } else {
226
                        $parser->error(
227
                            __('Unexpected keyword.'),
228
                            $token
229
                        );
230
                        break;
231
                    }
232
                    $state = 2;
233
                    $miniState = 1;
234
                } else {
235
                    $parser->error(
236
                        __('Unexpected token.'),
237
                        $token
238
                    );
239
                    break;
240
                }
241
            } elseif ($state == 2) {
242
                $lastCount = $miniState;
243
244
                if ($miniState === 1 && $token->value === 'ON') {
245
                    $miniState++;
246
                } elseif ($miniState === 2 && $token->value === 'DUPLICATE') {
247
                    $miniState++;
248
                } elseif ($miniState === 3 && $token->value === 'KEY') {
249
                    $miniState++;
250
                } elseif ($miniState === 4 && $token->value === 'UPDATE') {
251
                    $miniState++;
252
                }
253
254
                if ($lastCount === $miniState) {
255
                    $parser->error(
256
                        __('Unexpected token.'),
257
                        $token
258
                    );
259
                    break;
260
                }
261
262
                if ($miniState === 5) {
263
                    ++$list->idx;
264
                    $this->onDuplicateSet = SetOperation::parse($parser, $list);
265
                    $state = 3;
266
                }
267
            }
268
        }
269
270
        --$list->idx;
271
    }
272
}
273