These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * `INTO` keyword parser. |
||
5 | */ |
||
6 | |||
7 | namespace PhpMyAdmin\SqlParser\Components; |
||
8 | |||
9 | use PhpMyAdmin\SqlParser\Component; |
||
10 | use PhpMyAdmin\SqlParser\Parser; |
||
11 | use PhpMyAdmin\SqlParser\Token; |
||
12 | use PhpMyAdmin\SqlParser\TokensList; |
||
13 | |||
14 | /** |
||
15 | * `INTO` keyword parser. |
||
16 | * |
||
17 | * @category Keywords |
||
18 | * |
||
19 | * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+ |
||
20 | */ |
||
21 | class IntoKeyword extends Component |
||
22 | { |
||
23 | /** |
||
24 | * FIELDS/COLUMNS Options for `SELECT...INTO` statements. |
||
25 | * |
||
26 | * @var array |
||
27 | */ |
||
28 | public static $FIELDS_OPTIONS = array( |
||
29 | 'TERMINATED BY' => array(1, 'expr'), |
||
30 | 'OPTIONALLY' => 2, |
||
31 | 'ENCLOSED BY' => array(3, 'expr'), |
||
32 | 'ESCAPED BY' => array(4, 'expr'), |
||
33 | ); |
||
34 | |||
35 | /** |
||
36 | * LINES Options for `SELECT...INTO` statements. |
||
37 | * |
||
38 | * @var array |
||
39 | */ |
||
40 | public static $LINES_OPTIONS = array( |
||
41 | 'STARTING BY' => array(1, 'expr'), |
||
42 | 'TERMINATED BY' => array(2, 'expr'), |
||
43 | ); |
||
44 | |||
45 | /** |
||
46 | * Type of target (OUTFILE or SYMBOL). |
||
47 | * |
||
48 | * @var string |
||
49 | */ |
||
50 | public $type; |
||
51 | |||
52 | /** |
||
53 | * The destination, which can be a table or a file. |
||
54 | * |
||
55 | * @var string|Expression |
||
56 | */ |
||
57 | public $dest; |
||
58 | |||
59 | /** |
||
60 | * The name of the columns. |
||
61 | * |
||
62 | * @var array |
||
63 | */ |
||
64 | public $columns; |
||
65 | |||
66 | /** |
||
67 | * The values to be selected into (SELECT .. INTO @var1). |
||
68 | * |
||
69 | * @var Expression[] |
||
70 | */ |
||
71 | public $values; |
||
72 | |||
73 | /** |
||
74 | * Options for FIELDS/COLUMNS keyword. |
||
75 | * |
||
76 | * @var OptionsArray |
||
77 | * |
||
78 | * @see static::$FIELDS_OPTIONS |
||
79 | */ |
||
80 | public $fields_options; |
||
81 | |||
82 | /** |
||
83 | * Whether to use `FIELDS` or `COLUMNS` while building. |
||
84 | * |
||
85 | * @var bool |
||
86 | */ |
||
87 | public $fields_keyword; |
||
88 | |||
89 | /** |
||
90 | * Options for OPTIONS keyword. |
||
91 | * |
||
92 | * @var OptionsArray |
||
93 | * |
||
94 | * @see static::$LINES_OPTIONS |
||
95 | */ |
||
96 | public $lines_options; |
||
97 | |||
98 | /** |
||
99 | * Constructor. |
||
100 | * |
||
101 | * @param string $type Type of destination (may be OUTFILE). |
||
0 ignored issues
–
show
|
|||
102 | * @param string|Expression $dest Actual destination. |
||
0 ignored issues
–
show
Should the type for parameter
$dest not be string|Expression|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
103 | * @param array $columns Column list of destination. |
||
0 ignored issues
–
show
Should the type for parameter
$columns not be array|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
104 | * @param array $values Selected fields. |
||
0 ignored issues
–
show
Should the type for parameter
$values not be array|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
105 | * @param OptionsArray $fields_options Options for FIELDS/COLUMNS keyword. |
||
0 ignored issues
–
show
Should the type for parameter
$fields_options not be OptionsArray|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
106 | * @param OptionsArray $fields_keyword Options for OPTINOS keyword. |
||
0 ignored issues
–
show
Should the type for parameter
$fields_keyword not be OptionsArray|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
107 | */ |
||
108 | 36 | public function __construct( |
|
0 ignored issues
–
show
The parameter $fields_options is not named in camelCase.
This check marks parameter names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes
Loading history...
The parameter $fields_keyword is not named in camelCase.
This check marks parameter names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes
Loading history...
|
|||
109 | $type = null, |
||
110 | $dest = null, |
||
111 | $columns = null, |
||
112 | $values = null, |
||
113 | $fields_options = null, |
||
114 | $fields_keyword = null |
||
115 | ) { |
||
116 | 36 | $this->type = $type; |
|
117 | 36 | $this->dest = $dest; |
|
118 | 36 | $this->columns = $columns; |
|
0 ignored issues
–
show
It seems like
$columns can be null . However, the property $columns is declared as array . Maybe change the type of the property to array|null or add a type check?
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property. To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter. function aContainsB(array $needle = null, array $haystack) {
if (!$needle) {
return false;
}
return array_intersect($haystack, $needle) == $haystack;
}
The function can be called with either null or an array for the parameter
Loading history...
|
|||
119 | 36 | $this->values = $values; |
|
0 ignored issues
–
show
It seems like
$values can be null . However, the property $values is declared as array . Maybe change the type of the property to array|null or add a type check?
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property. To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter. function aContainsB(array $needle = null, array $haystack) {
if (!$needle) {
return false;
}
return array_intersect($haystack, $needle) == $haystack;
}
The function can be called with either null or an array for the parameter
Loading history...
|
|||
120 | 36 | $this->fields_options = $fields_options; |
|
121 | 36 | $this->fields_keyword = $fields_keyword; |
|
0 ignored issues
–
show
It seems like
$fields_keyword can also be of type object<PhpMyAdmin\SqlPar...omponents\OptionsArray> . However, the property $fields_keyword is declared as type boolean . 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 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...
|
|||
122 | 36 | } |
|
123 | |||
124 | /** |
||
125 | * @param Parser $parser the parser that serves as context |
||
126 | * @param TokensList $list the list of tokens that are being parsed |
||
127 | * @param array $options parameters for parsing |
||
128 | * |
||
129 | * @return IntoKeyword |
||
130 | */ |
||
131 | 36 | public static function parse(Parser $parser, TokensList $list, array $options = array()) |
|
132 | { |
||
133 | 36 | $ret = new self(); |
|
134 | |||
135 | /** |
||
136 | * The state of the parser. |
||
137 | * |
||
138 | * Below are the states of the parser. |
||
139 | * |
||
140 | * 0 -----------------------[ name ]----------------------> 1 |
||
141 | * 0 ---------------------[ OUTFILE ]---------------------> 2 |
||
142 | * |
||
143 | * 1 ------------------------[ ( ]------------------------> (END) |
||
144 | * |
||
145 | * 2 ---------------------[ filename ]--------------------> 1 |
||
146 | * |
||
147 | * @var int |
||
148 | */ |
||
149 | 36 | $state = 0; |
|
150 | |||
151 | 36 | for (; $list->idx < $list->count; ++$list->idx) { |
|
152 | /** |
||
153 | * Token parsed at this moment. |
||
154 | * |
||
155 | * @var Token |
||
156 | */ |
||
157 | 36 | $token = $list->tokens[$list->idx]; |
|
158 | |||
159 | // End of statement. |
||
160 | 36 | if ($token->type === Token::TYPE_DELIMITER) { |
|
161 | 7 | break; |
|
162 | } |
||
163 | |||
164 | // Skipping whitespaces and comments. |
||
165 | 36 | if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) { |
|
166 | 33 | continue; |
|
167 | } |
||
168 | |||
169 | 36 | if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_RESERVED)) { |
|
170 | 17 | if (($state === 0) && ($token->keyword === 'OUTFILE')) { |
|
171 | 10 | $ret->type = 'OUTFILE'; |
|
172 | 10 | $state = 2; |
|
173 | 10 | continue; |
|
174 | } |
||
175 | |||
176 | // No other keyword is expected except for $state = 4, which expects `LINES` |
||
177 | 12 | if ($state !== 4) { |
|
178 | 11 | break; |
|
179 | } |
||
180 | } |
||
181 | |||
182 | 35 | if ($state === 0) { |
|
183 | 26 | if ((isset($options['fromInsert']) |
|
184 | 12 | && $options['fromInsert']) |
|
185 | 14 | || (isset($options['fromReplace']) |
|
186 | 12 | && $options['fromReplace']) |
|
187 | ) { |
||
188 | 24 | $ret->dest = Expression::parse( |
|
189 | 24 | $parser, |
|
190 | 24 | $list, |
|
191 | array( |
||
192 | 24 | 'parseField' => 'table', |
|
193 | 'breakOnAlias' => true, |
||
194 | ) |
||
195 | ); |
||
196 | } else { |
||
197 | 2 | $ret->values = ExpressionArray::parse($parser, $list); |
|
198 | } |
||
199 | 26 | $state = 1; |
|
200 | 27 | } elseif ($state === 1) { |
|
201 | 18 | if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) { |
|
202 | 16 | $ret->columns = ArrayObj::parse($parser, $list)->values; |
|
203 | 16 | ++$list->idx; |
|
204 | } |
||
205 | 18 | break; |
|
206 | 9 | } elseif ($state === 2) { |
|
207 | 9 | $ret->dest = $token->value; |
|
208 | |||
209 | 9 | $state = 3; |
|
210 | 4 | } elseif ($state == 3) { |
|
211 | 4 | $ret->parseFileOptions($parser, $list, $token->value); |
|
212 | 4 | $state = 4; |
|
213 | 4 | } elseif ($state == 4) { |
|
214 | 4 | if ($token->type === Token::TYPE_KEYWORD && $token->keyword !== 'LINES') { |
|
215 | 1 | break; |
|
216 | } |
||
217 | |||
218 | 3 | $ret->parseFileOptions($parser, $list, $token->value); |
|
219 | 3 | $state = 5; |
|
220 | } |
||
221 | } |
||
222 | |||
223 | 36 | --$list->idx; |
|
224 | |||
225 | 36 | return $ret; |
|
226 | } |
||
227 | |||
228 | 4 | public function parseFileOptions(Parser $parser, TokensList $list, $keyword = 'FIELDS') |
|
229 | { |
||
230 | 4 | ++$list->idx; |
|
231 | |||
232 | 4 | if ($keyword === 'FIELDS' || $keyword === 'COLUMNS') { |
|
233 | // parse field options |
||
234 | 4 | $this->fields_options = OptionsArray::parse( |
|
235 | 4 | $parser, |
|
236 | 4 | $list, |
|
237 | 4 | static::$FIELDS_OPTIONS |
|
238 | ); |
||
239 | |||
240 | 4 | if ($keyword === 'FIELDS') { |
|
241 | 1 | $this->fields_keyword = true; |
|
242 | } else { |
||
243 | 3 | $this->fields_keyword = false; |
|
244 | } |
||
245 | } else { |
||
246 | // parse line options |
||
247 | 3 | $this->lines_options = OptionsArray::parse( |
|
248 | 3 | $parser, |
|
249 | 3 | $list, |
|
250 | 3 | static::$LINES_OPTIONS |
|
251 | ); |
||
252 | } |
||
253 | 4 | } |
|
254 | |||
255 | /** |
||
256 | * @param IntoKeyword $component the component to be built |
||
257 | * @param array $options parameters for building |
||
258 | * |
||
259 | * @return string |
||
260 | */ |
||
261 | 8 | public static function build($component, array $options = array()) |
|
262 | { |
||
263 | 8 | if ($component->dest instanceof Expression) { |
|
264 | 4 | $columns = !empty($component->columns) ? '(`' . implode('`, `', $component->columns) . '`)' : ''; |
|
265 | |||
266 | 4 | return $component->dest . $columns; |
|
267 | 4 | } elseif (isset($component->values)) { |
|
268 | 2 | return ExpressionArray::build($component->values); |
|
0 ignored issues
–
show
$component->values is of type array<integer,object<Php...Components\Expression>> , but the function expects a array<integer,object<Php...nents\ExpressionArray>> .
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...
|
|||
269 | } |
||
270 | |||
271 | 2 | $ret = 'OUTFILE "' . $component->dest . '"'; |
|
272 | |||
273 | 2 | $fields_options_str = OptionsArray::build($component->fields_options); |
|
274 | 2 | if (trim($fields_options_str) !== '') { |
|
275 | 1 | $ret .= ($component->fields_keyword) ? ' FIELDS' : ' COLUMNS'; |
|
276 | 1 | $ret .= ' ' . $fields_options_str; |
|
277 | } |
||
278 | |||
279 | 2 | $lines_options_str = OptionsArray::build($component->lines_options, array('expr' => true)); |
|
280 | 2 | if (trim($lines_options_str) !== '') { |
|
281 | 1 | $ret .= ' LINES ' . $lines_options_str; |
|
282 | } |
||
283 | |||
284 | 2 | return $ret; |
|
285 | } |
||
286 | } |
||
287 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.