Completed
Pull Request — master (#76)
by Deven
124:52 queued 60:08
created

InsertStatement::parse()   D

Complexity

Conditions 25
Paths 10

Size

Total Lines 127
Code Lines 68

Duplication

Lines 9
Ratio 7.09 %

Code Coverage

Tests 0
CRAP Score 650

Importance

Changes 0
Metric Value
cc 25
eloc 68
nc 10
nop 2
dl 9
loc 127
ccs 0
cts 0
cp 0
crap 650
rs 4.5682
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\OptionsArray;
19
use SqlParser\Components\SetOperation;
20
21
/**
22
 * `INSERT` statement.
23
 *
24
 * INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
25
 *     [INTO] tbl_name
26
 *     [PARTITION (partition_name,...)]
27
 *     [(col_name,...)]
28
 *     {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
29
 *     [ ON DUPLICATE KEY UPDATE
30
 *       col_name=expr
31
 *         [, col_name=expr] ... ]
32
 *
33
 * or
34
 *
35
 * INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
36
 *     [INTO] tbl_name
37
 *     [PARTITION (partition_name,...)]
38
 *     SET col_name={expr | DEFAULT}, ...
39
 *     [ ON DUPLICATE KEY UPDATE
40
 *       col_name=expr
41
 *         [, col_name=expr] ... ]
42
 *
43
 * or
44
 *
45
 * INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
46
 *     [INTO] tbl_name
47
 *     [PARTITION (partition_name,...)]
48
 *     [(col_name,...)]
49
 *     SELECT ...
50
 *     [ ON DUPLICATE KEY UPDATE
51
 *       col_name=expr
52
 *         [, col_name=expr] ... ]
53
 *
54
 * @category   Statements
55
 * @package    SqlParser
56
 * @subpackage Statements
57
 * @author     Dan Ungureanu <[email protected]>
58
 * @license    http://opensource.org/licenses/GPL-2.0 GNU Public License
59
 */
60
class InsertStatement extends Statement
61
{
62
63
    /**
64
     * Options for `INSERT` statements.
65
     *
66
     * @var array
67
     */
68
    public static $OPTIONS = array(
69
        'LOW_PRIORITY'                  => 1,
70
        'DELAYED'                       => 2,
71
        'HIGH_PRIORITY'                 => 3,
72
        'IGNORE'                        => 4,
73
    );
74
75
    /**
76
     * Tables used as target for this statement.
77
     *
78
     * @var IntoKeyword
79
     */
80
    public $into;
81
82
    /**
83
     * Values to be inserted.
84
     *
85
     * @var Array2d
86
     */
87 1
    public $values;
88
89 1
    /**
90 1
     * If SET clause is present
91 1
     * holds the SetOperation
92
     *
93
     * @var SetOperation[]
94
     */
95
    public $set;
96
97
    /**
98
     * If SELECT clause is present
99
     * holds the SelectStatement
100
     *
101
     * @var SelectStatement
102
     */
103
    public $select;
104
105
    /**
106
     * If ON DUPLICATE KEY UPDATE clause is present
107
     * holds the SetOperation
108
     *
109
     * @var SetOperation[]
110
     */
111
    public $onDuplicateSet;
112
113
    /**
114
     * @return string
115
     */
116
    public function build()
117
    {
118
        $ret = 'INSERT ' . $this->options
119
            . ' INTO ' . $this->into;
120
121
        if ($this->values != NULL && count($this->values) > 0) {
122
            $ret .= ' VALUES ' . Array2d::build($this->values);
0 ignored issues
show
Documentation introduced by
$this->values is of type object<SqlParser\Components\Array2d>, but the function expects a array<integer,object<Sql...r\Components\ArrayObj>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
123 View Code Duplication
        } elseif ($this->set != NULL && count($this->set) > 0) {
124
            $ret .= ' SET ' . SetOperation::build($this->set);
125
        } elseif ($this->select != NULL && count($this->select) > 0) {
126
            $ret .= ' ' . $this->select->build();
127
        }
128
129 View Code Duplication
        if ($this->onDuplicateSet != NULL && count($this->onDuplicateSet) > 0) {
130
            $ret .= ' ON DUPLICATE KEY UPDATE ' . SetOperation::build($this->onDuplicateSet);
131
        }
132
133
        return $ret;
134
135
    }
136
137
138
    /**
139
     * @param Parser     $parser The instance that requests parsing.
140
     * @param TokensList $list   The list of tokens to be parsed.
141
     *
142
     * @return void
143
     */
144
    public function parse(Parser $parser, TokensList $list)
145
    {
146
        ++$list->idx; // Skipping `INSERT`.
147
148
        // parse any options if provided
149
        $this->options = OptionsArray::parse(
150
            $parser,
151
            $list,
152
            static::$OPTIONS
153
        );
154
        ++$list->idx;
155
156
        $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...
157
158
        /**
159
         * The state of the parser.
160
         *
161
         * Below are the states of the parser.
162
         *
163
         *      0 ---------------------------------[ INTO ]----------------------------------> 1
164
         *
165
         *      1 -------------------------[ VALUES/VALUE/SET/SELECT ]-----------------------> 2
166
         *
167
         *      2 -------------------------[ ON DUPLICATE KEY UPDATE ]-----------------------> 3
168
         *
169
         * @var int $state
170
         */
171
        $state = 0;
172
173
        /**
174
         * For keeping track of semi-states on encountering
175
         * ON DUPLICATE KEY UPDATE ...
176
         *
177
         */
178
        $miniState = 0;
179
180
        for (; $list->idx < $list->count; ++$list->idx) {
181
            /**
182
             * Token parsed at this moment.
183
             *
184
             * @var Token $token
185
             */
186
            $token = $list->tokens[$list->idx];
187
188
            // End of statement.
189
            if ($token->type === Token::TYPE_DELIMITER) {
190
                break;
191
            }
192
193
            // Skipping whitespaces and comments.
194
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
195
                continue;
196
            }
197
198
            if ($state === 0) {
199 View Code Duplication
                if ($token->type === Token::TYPE_KEYWORD
200
                    && $token->value !== 'INTO'
201
                ) {
202
                    $parser->error(__('Unexpected keyword.'), $token);
203
                    break;
204
                } else {
205
                    ++$list->idx;
206
                    $this->into = IntoKeyword::parse($parser, $list);
207
                }
208
209
                $state = 1;
210
            } elseif ($state === 1) {
211
                if ($token->type === Token::TYPE_KEYWORD) {
212
                    if ($token->value === 'VALUE'
213
                        || $token->value === 'VALUES'
214
                    ) {
215
                        ++$list->idx; // skip VALUES
216
217
                        $this->values = Array2d::parse($parser, $list);
0 ignored issues
show
Documentation Bug introduced by
It seems like \SqlParser\Components\Ar...::parse($parser, $list) of type array<integer,object<Sql...r\Components\ArrayObj>> is incompatible with the declared type object<SqlParser\Components\Array2d> of property $values.

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...
218
                    } elseif ($token->value === 'SET') {
219
                        ++$list->idx; // skip SET
220
221
                        $this->set = SetOperation::parse($parser, $list);
222
                    } elseif ($token->value === 'SELECT') {
223
                        $this->select = new SelectStatement($parser, $list);
224
                    } else {
225
                        $parser->error(
226
                            __('Unexpected keyword.'),
227
                            $token
228
                        );
229
                        break;
230
                    }
231
                    $state = 2;
232
                    $miniState = 1;
233
                } else {
234
                    $parser->error(
235
                        __('Unexpected token.'),
236
                        $token
237
                    );
238
                    break;
239
                }
240
            } elseif ($state == 2) {
241
                $lastCount = $miniState;
242
243
                if ($miniState === 1 && $token->value === 'ON') {
244
                    $miniState++;
245
                } elseif ($miniState === 2 && $token->value === 'DUPLICATE') {
246
                    $miniState++;
247
                } elseif ($miniState === 3 && $token->value === 'KEY') {
248
                    $miniState++;
249
                } elseif ($miniState === 4 && $token->value === 'UPDATE') {
250
                    $miniState++;
251
                }
252
253
                if ($lastCount === $miniState) {
254
                    $parser->error(
255
                        __('Unexpected token.'),
256
                        $token
257
                    );
258
                    break;
259
                }
260
261
                if ($miniState === 5) {
262
                    ++$list->idx;
263
                    $this->onDuplicateSet = SetOperation::parse($parser, $list);
264
                    $state = 3;
265
                }
266
            }
267
        }
268
269
        --$list->idx;
270
    }
271
}
272