Skip to content

Commit 582f9e6

Browse files
authored
Merge pull request #90 from devenbansod/subquery_in_from
Fix parsing of subquery in FROM clause
2 parents 280c72f + 31e346b commit 582f9e6

18 files changed

+97
-20
lines changed

src/Components/IntoKeyword.php

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ class IntoKeyword extends Component
4545
*/
4646
public $columns;
4747

48+
/**
49+
* The values to be selected into (SELECT .. INTO @var1)
50+
*
51+
* @var ExpressionArray
52+
*/
53+
public $values;
54+
4855
/**
4956
* @param Parser $parser The parser that serves as context.
5057
* @param TokensList $list The list of tokens that are being parsed.
@@ -102,14 +109,22 @@ public static function parse(Parser $parser, TokensList $list, array $options =
102109
}
103110

104111
if ($state === 0) {
105-
$ret->dest = Expression::parse(
106-
$parser,
107-
$list,
108-
array(
109-
'parseField' => 'table',
110-
'breakOnAlias' => true,
111-
)
112-
);
112+
if ((isset($options['fromInsert'])
113+
&& $options['fromInsert'])
114+
|| (isset($options['fromReplace'])
115+
&& $options['fromReplace'])
116+
) {
117+
$ret->dest = Expression::parse(
118+
$parser,
119+
$list,
120+
array(
121+
'parseField' => 'table',
122+
'breakOnAlias' => true,
123+
)
124+
);
125+
} else {
126+
$ret->values = ExpressionArray::parse($parser, $list);
127+
}
113128
$state = 1;
114129
} elseif ($state === 1) {
115130
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
@@ -140,8 +155,10 @@ public static function build($component, array $options = array())
140155
$columns = !empty($component->columns) ?
141156
'(`' . implode('`, `', $component->columns) . '`)' : '';
142157
return $component->dest . $columns;
158+
} elseif (isset($component->values)) {
159+
return ExpressionArray::build($component->values);
143160
} else {
144161
return 'OUTFILE "' . $component->dest . '"';
145162
}
146163
}
147-
}
164+
}

src/Components/JoinKeyword.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ public static function parse(Parser $parser, TokensList $list, array $options =
146146
$state = 3;
147147
} elseif ($token->value === 'USING') {
148148
$state = 4;
149+
} else {
150+
/* Next clause is starting */
151+
break;
149152
}
150153
}
151154
} elseif ($state === 3) {
@@ -182,8 +185,9 @@ public static function build($component, array $options = array())
182185
foreach ($component as $c) {
183186
$ret[] = array_search($c->type, static::$JOINS) . ' ' . $c->expr
184187
. (!empty($c->on)
185-
? ' ON ' . Condition::build($c->on)
186-
: ' USING ' . ArrayObj::build($c->using));
188+
? ' ON ' . Condition::build($c->on) : '')
189+
. (!empty($c->using)
190+
? ' USING ' . ArrayObj::build($c->using) : '');
187191
}
188192
return implode(' ', $ret);
189193
}

src/Parser.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class Parser
162162
'FROM' => array(
163163
'class' => 'SqlParser\\Components\\ExpressionArray',
164164
'field' => 'from',
165-
'options' => array('parseField' => 'table'),
165+
'options' => array('field' => 'table'),
166166
),
167167
'GROUP BY' => array(
168168
'class' => 'SqlParser\\Components\\OrderKeyword',

src/Statements/InsertStatement.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,11 @@ public function parse(Parser $parser, TokensList $list)
200200
break;
201201
} else {
202202
++$list->idx;
203-
$this->into = IntoKeyword::parse($parser, $list);
203+
$this->into = IntoKeyword::parse(
204+
$parser,
205+
$list,
206+
array('fromInsert' => true)
207+
);
204208
}
205209

206210
$state = 1;

src/Statements/ReplaceStatement.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ public function parse(Parser $parser, TokensList $list)
166166
break;
167167
} else {
168168
++$list->idx;
169-
$this->into = IntoKeyword::parse($parser, $list);
169+
$this->into = IntoKeyword::parse(
170+
$parser,
171+
$list,
172+
array('fromReplace' => true)
173+
);
170174
}
171175

172176
$state = 1;

src/Statements/SelectStatement.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class SelectStatement extends Statement
8787
'_OPTIONS' => array('_OPTIONS', 1),
8888
// Used for selected expressions.
8989
'_SELECT' => array('SELECT', 1),
90+
'INTO' => array('INTO', 3),
9091
'FROM' => array('FROM', 3),
9192
'PARTITION' => array('PARTITION', 3),
9293

@@ -104,7 +105,6 @@ class SelectStatement extends Statement
104105
'ORDER BY' => array('ORDER BY', 3),
105106
'LIMIT' => array('LIMIT', 3),
106107
'PROCEDURE' => array('PROCEDURE', 3),
107-
'INTO' => array('INTO', 3),
108108
'UNION' => array('UNION', 1),
109109
// These are available only when `UNION` is present.
110110
// 'ORDER BY' => array('ORDER BY', 3),

tests/Components/IntoKeywordTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public function testBuild()
2323
$this->assertEquals('tbl(`col1`, `col2`)', IntoKeyword::build($component));
2424
}
2525

26+
public function testBuildValues()
27+
{
28+
$component = IntoKeyword::parse(new Parser(), $this->getTokensList('@a1, @a2, @a3'));
29+
$this->assertEquals('@a1, @a2, @a3', IntoKeyword::build($component));
30+
}
31+
2632
public function testBuildOutfile()
2733
{
2834
$component = IntoKeyword::parse(new Parser(), $this->getTokensList('OUTFILE "/tmp/outfile.txt"'));

tests/Parser/SelectStatementTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ public function testSelectProvider()
3131
array('parser/parseSelect2'),
3232
array('parser/parseSelect3'),
3333
array('parser/parseSelect4'),
34+
array('parser/parseSelect5'),
35+
array('parser/parseSelect6'),
36+
array('parser/parseSelect7'),
37+
array('parser/parseSelect8'),
3438
array('parser/parseSelectErr1'),
3539
array('parser/parseSelectNested'),
3640
array('parser/parseSelectCase1'),

tests/Utils/QueryTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ public function testReplaceClauseOnlyKeyword()
457457
);
458458
}
459459

460-
public function testRepalceClauses()
460+
public function testReplaceClauses()
461461
{
462462
$this->assertEquals('', Query::replaceClauses(null, null, array()));
463463

@@ -475,18 +475,18 @@ public function testRepalceClauses()
475475

476476
$parser = new Parser(
477477
'SELECT c.city_id, c.country_id ' .
478+
'INTO OUTFILE "/dev/null" ' .
478479
'FROM `city` ' .
479480
'WHERE city_id < 1 ' .
480481
'ORDER BY city_id ASC ' .
481-
'LIMIT 0, 1 ' .
482-
'INTO OUTFILE "/dev/null"'
482+
'LIMIT 0, 1 '
483483
);
484484
$this->assertEquals(
485485
'SELECT c.city_id, c.country_id ' .
486+
'INTO OUTFILE "/dev/null" ' .
486487
'FROM city AS c ' .
487488
'ORDER BY city_id ASC ' .
488-
'LIMIT 0, 10 ' .
489-
'INTO OUTFILE "/dev/null"',
489+
'LIMIT 0, 10 ',
490490
Query::replaceClauses(
491491
$parser->statements[0],
492492
$parser->list,

tests/data/parser/parseSelect5.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SELECT c1, c2, c3
2+
/* Subquery in FROM list */
3+
FROM (SELECT C1, c2, c3 FROM test2) t1
4+
WHERE RIGHT(name, 2) = 'AB';

0 commit comments

Comments
 (0)