Skip to content

Commit f23527c

Browse files
committed
Fix parsing of FIELDS and LINES options in SELECT..INTO
Fix #105 Signed-off-by: Deven Bansod <[email protected]>
1 parent f97bf2d commit f23527c

File tree

7 files changed

+131
-25
lines changed

7 files changed

+131
-25
lines changed

src/Components/IntoKeyword.php

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,30 @@
2424
class IntoKeyword extends Component
2525
{
2626

27+
/**
28+
* FIELDS/COLUMNS Options for `SELECT...INTO` statements.
29+
*
30+
* @var array
31+
*/
32+
public static $FIELDS_OPTIONS = array(
33+
34+
'TERMINATED BY' => array(1, 'expr'),
35+
'OPTIONALLY' => 2,
36+
'ENCLOSED BY' => array(3, 'expr'),
37+
'ESCAPED BY' => array(4, 'expr'),
38+
);
39+
40+
/**
41+
* LINES Options for `SELECT...INTO` statements.
42+
*
43+
* @var array
44+
*/
45+
public static $LINES_OPTIONS = array(
46+
47+
'STARTING BY' => array(1, 'expr'),
48+
'TERMINATED BY' => array(2, 'expr'),
49+
);
50+
2751
/**
2852
* Type of target (OUTFILE or SYMBOL).
2953
*
@@ -52,6 +76,29 @@ class IntoKeyword extends Component
5276
*/
5377
public $values;
5478

79+
/**
80+
* Options for FIELDS/COLUMNS keyword
81+
*
82+
* @var OptionsArray
83+
* @see static::$FIELDS_OPTIONS
84+
*/
85+
public $fields_options;
86+
87+
/**
88+
* Whether to use `FIELDS` or `COLUMNS` while building
89+
*
90+
* @var boolean
91+
*/
92+
public $fields_keyword;
93+
94+
/**
95+
* Options for OPTIONS keyword
96+
*
97+
* @var OptionsArray
98+
* @see static::$LINES_OPTIONS
99+
*/
100+
public $lines_options;
101+
55102
/**
56103
* @param Parser $parser The parser that serves as context.
57104
* @param TokensList $list The list of tokens that are being parsed.
@@ -104,8 +151,10 @@ public static function parse(Parser $parser, TokensList $list, array $options =
104151
continue;
105152
}
106153

107-
// No other keyword is expected.
108-
break;
154+
// No other keyword is expected except for $state = 4, which expects `LINES`
155+
if ($state !== 4) {
156+
break;
157+
}
109158
}
110159

111160
if ($state === 0) {
@@ -134,15 +183,55 @@ public static function parse(Parser $parser, TokensList $list, array $options =
134183
break;
135184
} elseif ($state === 2) {
136185
$ret->dest = $token->value;
137-
++$list->idx;
138-
break;
186+
187+
$state = 3;
188+
} elseif ($state == 3) {
189+
$ret->_parseFileOptions($parser, $list, $token->value);
190+
$state = 4;
191+
} elseif ($state == 4) {
192+
if ($token->type === Token::TYPE_KEYWORD && $token->value !== 'LINES') {
193+
$parser->error(
194+
__('Unexpected keyword.'),
195+
$token
196+
);
197+
break;
198+
}
199+
200+
$ret->_parseFileOptions($parser, $list, $token->value);
201+
$state = 5;
139202
}
140203
}
141204

142205
--$list->idx;
143206
return $ret;
144207
}
145208

209+
private function _parseFileOptions(Parser $parser, TokensList $list, $keyword='FIELDS') {
210+
++$list->idx;
211+
212+
if ($keyword === 'FIELDS' || $keyword === 'COLUMNS') {
213+
// parse field options
214+
$this->fields_options = OptionsArray::parse(
215+
$parser,
216+
$list,
217+
static::$FIELDS_OPTIONS
218+
);
219+
220+
if ($keyword === 'FIELDS') {
221+
$this->fields_keyword = true;
222+
} else {
223+
$this->fields_keyword = false;
224+
}
225+
} else {
226+
// parse line options
227+
$this->lines_options = OptionsArray::parse(
228+
$parser,
229+
$list,
230+
static::$LINES_OPTIONS
231+
);
232+
}
233+
}
234+
146235
/**
147236
* @param IntoKeyword $component The component to be built.
148237
* @param array $options Parameters for building.
@@ -158,7 +247,20 @@ public static function build($component, array $options = array())
158247
} elseif (isset($component->values)) {
159248
return ExpressionArray::build($component->values);
160249
} else {
161-
return 'OUTFILE "' . $component->dest . '"';
250+
$ret = 'OUTFILE "' . $component->dest . '"';
251+
252+
$fields_options_str = OptionsArray::build($component->fields_options);
253+
if (trim($fields_options_str) !== '') {
254+
$ret .= ($component->fields_keyword) ? ' FIELDS' : ' COLUMNS';
255+
$ret .= ' ' . $fields_options_str;
256+
}
257+
258+
$lines_options_str = OptionsArray::build($component->lines_options, array('expr' => true));
259+
if (trim($lines_options_str) !== '') {
260+
$ret .= ' LINES ' . $lines_options_str;
261+
}
262+
263+
return $ret;
162264
}
163265
}
164266
}

src/Contexts/ContextMySql50000.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,12 @@ class ContextMySql50000 extends Context
145145
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
146146
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
147147
'UNION ALL' => 7,
148-
'CROSS JOIN' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7,
149-
'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
150-
'LINEAR HASH' => 7,
148+
'CROSS JOIN' => 7, 'ESCAPED BY' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7,
149+
'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
150+
'ENCLOSED BY' => 7, 'LINEAR HASH' => 7, 'STARTING BY' => 7,
151151
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
152152
'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
153-
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
153+
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'TERMINATED BY' => 7,
154154
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
155155
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
156156
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,

src/Contexts/ContextMySql50100.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,12 @@ class ContextMySql50100 extends Context
159159
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
160160
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
161161
'UNION ALL' => 7,
162-
'CROSS JOIN' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7,
163-
'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
164-
'LINEAR HASH' => 7,
162+
'CROSS JOIN' => 7, 'ESCAPED BY' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7,
163+
'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
164+
'ENCLOSED BY' => 7, 'LINEAR HASH' => 7, 'STARTING BY' => 7,
165165
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
166166
'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
167-
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
167+
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'TERMINATED BY' => 7,
168168
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
169169
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
170170
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,

src/Contexts/ContextMySql50500.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,12 @@ class ContextMySql50500 extends Context
163163
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
164164
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
165165
'UNION ALL' => 7,
166-
'CROSS JOIN' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7,
167-
'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
168-
'LINEAR HASH' => 7,
166+
'CROSS JOIN' => 7, 'ESCAPED BY' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7,
167+
'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
168+
'ENCLOSED BY' => 7, 'LINEAR HASH' => 7, 'STARTING BY' => 7,
169169
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
170170
'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
171-
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
171+
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'TERMINATED BY' => 7,
172172
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
173173
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
174174
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,

src/Contexts/ContextMySql50600.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,12 @@ class ContextMySql50600 extends Context
169169
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
170170
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
171171
'UNION ALL' => 7,
172-
'CROSS JOIN' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7,
173-
'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
174-
'LINEAR HASH' => 7,
172+
'CROSS JOIN' => 7, 'ESCAPED BY' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7,
173+
'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
174+
'ENCLOSED BY' => 7, 'LINEAR HASH' => 7, 'STARTING BY' => 7,
175175
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
176176
'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
177-
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
177+
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'TERMINATED BY' => 7,
178178
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
179179
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
180180
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,

src/Contexts/ContextMySql50700.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,12 @@ class ContextMySql50700 extends Context
175175
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
176176
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
177177
'UNION ALL' => 7,
178-
'CROSS JOIN' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7,
179-
'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
180-
'LINEAR HASH' => 7,
178+
'CROSS JOIN' => 7, 'ESCAPED BY' => 7, 'FOR UPDATE' => 7, 'INNER JOIN' => 7,
179+
'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
180+
'ENCLOSED BY' => 7, 'LINEAR HASH' => 7, 'STARTING BY' => 7,
181181
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
182182
'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
183-
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
183+
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'TERMINATED BY' => 7,
184184
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
185185
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
186186
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,

tools/contexts/_common.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ DEFAULT CHARACTER SET
2121
DEFAULT CHARSET
2222
DEFAULT COLLATE
2323
DOUBLE (D)
24+
ENCLOSED BY
2425
ENUM (D)
26+
ESCAPED BY
2527
FLOAT (D)
2628
FOR EACH ROW
2729
FOR UPDATE
@@ -96,8 +98,10 @@ SPATIAL INDEX (K)
9698
SPATIAL KEY (K)
9799
SQL SECURITY
98100
START TRANSACTION
101+
STARTING BY
99102
SUBPARTITION BY
100103
SUBPARTITIONS
104+
TERMINATED BY
101105
TEXT (D)
102106
TIME (D)
103107
TIMESTAMP (D)

0 commit comments

Comments
 (0)