Skip to content
This repository was archived by the owner on Sep 23, 2025. It is now read-only.

Commit d817c21

Browse files
authored
Merge pull request #507 from kitta65/feature/by-name-corresponding
by name / corresponding
2 parents 572ea75 + ac39641 commit d817c21

3 files changed

Lines changed: 264 additions & 24 deletions

File tree

src/parser.rs

Lines changed: 95 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,79 @@ impl Parser {
949949
}
950950
Ok(nodes)
951951
}
952+
fn parse_set_operator(&mut self, left: Node) -> BQ2CSTResult<Node> {
953+
let mut operator: Node;
954+
if self
955+
.get_token(0)?
956+
.in_(&vec!["INNER", "FULL", "LEFT", "OUTER"])
957+
{
958+
let mut method;
959+
if self.get_token(0)?.in_(&vec!["INNER", "OUTER"]) {
960+
method = self.construct_node(NodeType::Keyword)?;
961+
} else {
962+
method = self.construct_node(NodeType::KeywordSequence)?;
963+
self.next_token()?; // -> OUTER
964+
let outer = self.construct_node(NodeType::Keyword)?;
965+
method.push_node("next_keyword", outer);
966+
}
967+
968+
self.next_token()?; // -> UNION
969+
operator = self.construct_node(NodeType::SetOperator)?;
970+
operator.push_node("method", method);
971+
} else {
972+
operator = self.construct_node(NodeType::SetOperator)?;
973+
}
974+
self.next_token()?; // ALL | DISTINCT
975+
operator.push_node("distinct_or_all", self.construct_node(NodeType::Keyword)?);
976+
977+
if self.get_token(1)?.is("BY") {
978+
self.next_token()?; // -> BY
979+
let mut by = self.construct_node(NodeType::KeywordSequence)?;
980+
self.next_token()?; // -> NAME
981+
let mut name: Node;
982+
if self.get_token(1)?.is("ON") {
983+
name = self.construct_node(NodeType::KeywordSequence)?;
984+
self.next_token()?; // -> ON
985+
let mut on = self.construct_node(NodeType::KeywordWithExpr)?;
986+
self.next_token()?; // -> (
987+
let columns = self.parse_grouped_exprs(false)?;
988+
989+
on.push_node("expr", columns);
990+
name.push_node("next_keyword", on);
991+
} else {
992+
name = self.construct_node(NodeType::Keyword)?;
993+
}
994+
by.push_node("next_keyword", name);
995+
operator.push_node("by", by);
996+
} else if self.get_token(1)?.in_(&vec!["STRICT", "CORRESPONDING"]) {
997+
self.next_token()?; // -> STRICT | CORRESPONDING
998+
let mut strict_exists = false;
999+
let mut strict = Node::empty(NodeType::Unknown);
1000+
if self.get_token(0)?.is("STRICT") {
1001+
strict_exists = true;
1002+
strict = self.construct_node(NodeType::KeywordSequence)?;
1003+
self.next_token()?; // -> CORRESPONDING
1004+
}
1005+
let mut corresponding = self.construct_node(NodeType::Keyword)?;
1006+
if self.get_token(1)?.is("BY") {
1007+
corresponding.node_type = NodeType::KeywordSequence;
1008+
self.next_token()?; // -> BY
1009+
let mut by = self.construct_node(NodeType::KeywordWithExpr)?;
1010+
self.next_token()?; // -> (
1011+
by.push_node("expr", self.parse_grouped_exprs(false)?);
1012+
corresponding.push_node("next_keyword", by);
1013+
}
1014+
if strict_exists {
1015+
strict.push_node("next_keyword", corresponding);
1016+
corresponding = strict;
1017+
}
1018+
operator.push_node("corresponding", corresponding);
1019+
}
1020+
operator.push_node("left", left);
1021+
self.next_token()?; // DISTINCT -> stmt
1022+
operator.push_node("right", self.parse_select_statement(false, false)?);
1023+
Ok(operator)
1024+
}
9521025
fn parse_statement(&mut self, semicolon: bool) -> BQ2CSTResult<Node> {
9531026
let node = match self.get_token(0)?.literal.to_uppercase().as_str() {
9541027
// SELECT
@@ -1588,19 +1661,18 @@ impl Parser {
15881661
));
15891662
}
15901663
node.push_node("rparen", self.construct_node(NodeType::Symbol)?);
1591-
while self
1592-
.get_token(1)?
1593-
.in_(&vec!["UNION", "INTERSECT", "EXCEPT"])
1594-
&& root
1664+
while self.get_token(1)?.in_(&vec![
1665+
"UNION",
1666+
"INTERSECT",
1667+
"EXCEPT",
1668+
"INNER",
1669+
"FULL",
1670+
"LEFT",
1671+
"OUTER",
1672+
]) && root
15951673
{
1596-
self.next_token()?; // stmt -> UNION
1597-
let mut operator = self.construct_node(NodeType::SetOperator)?;
1598-
self.next_token()?; // UNION -> DISTINCT
1599-
operator.push_node("distinct_or_all", self.construct_node(NodeType::Keyword)?);
1600-
operator.push_node("left", node);
1601-
self.next_token()?; // DISTINCT -> stmt
1602-
operator.push_node("right", self.parse_select_statement(false, false)?);
1603-
node = operator;
1674+
self.next_token()?;
1675+
node = self.parse_set_operator(node)?;
16041676
}
16051677
// ORDER BY
16061678
if self.get_token(1)?.is("ORDER") && root {
@@ -1811,19 +1883,18 @@ impl Parser {
18111883
node.push_node("limit", limit);
18121884
}
18131885
// UNION
1814-
while self
1815-
.get_token(1)?
1816-
.in_(&vec!["UNION", "INTERSECT", "EXCEPT"])
1817-
&& root
1886+
while self.get_token(1)?.in_(&vec![
1887+
"UNION",
1888+
"INTERSECT",
1889+
"EXCEPT",
1890+
"INNER",
1891+
"FULL",
1892+
"LEFT",
1893+
"OUTER",
1894+
]) && root
18181895
{
1819-
self.next_token()?; // stmt -> UNION
1820-
let mut operator = self.construct_node(NodeType::SetOperator)?;
1821-
self.next_token()?; // UNION -> DISTINCT
1822-
operator.push_node("distinct_or_all", self.construct_node(NodeType::Keyword)?);
1823-
operator.push_node("left", node);
1824-
self.next_token()?; // DISTINCT -> stmt
1825-
operator.push_node("right", self.parse_select_statement(false, false)?);
1826-
node = operator;
1896+
self.next_token()?;
1897+
node = self.parse_set_operator(node)?;
18271898
}
18281899
// ;
18291900
if self.get_token(1)?.is(";") && semicolon {

src/parser/tests/tests_select.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,173 @@ right:
366366
self: SELECT (SelectStatement)
367367
exprs:
368368
- self: 3 (NumericLiteral)
369+
",
370+
0,
371+
)),
372+
Box::new(SuccessTestCase::new(
373+
"\
374+
SELECT 1 INNER UNION ALL BY NAME SELECT 2
375+
",
376+
"\
377+
self: UNION (SetOperator)
378+
by:
379+
self: BY (KeywordSequence)
380+
next_keyword:
381+
self: NAME (Keyword)
382+
distinct_or_all:
383+
self: ALL (Keyword)
384+
left:
385+
self: SELECT (SelectStatement)
386+
exprs:
387+
- self: 1 (NumericLiteral)
388+
method:
389+
self: INNER (Keyword)
390+
right:
391+
self: SELECT (SelectStatement)
392+
exprs:
393+
- self: 2 (NumericLiteral)
394+
",
395+
0,
396+
)),
397+
Box::new(SuccessTestCase::new(
398+
"\
399+
SELECT 1 FULL OUTER UNION ALL BY NAME ON (foo) SELECT 2
400+
",
401+
"\
402+
self: UNION (SetOperator)
403+
by:
404+
self: BY (KeywordSequence)
405+
next_keyword:
406+
self: NAME (KeywordSequence)
407+
next_keyword:
408+
self: ON (KeywordWithExpr)
409+
expr:
410+
self: ( (GroupedExprs)
411+
exprs:
412+
- self: foo (Identifier)
413+
rparen:
414+
self: ) (Symbol)
415+
distinct_or_all:
416+
self: ALL (Keyword)
417+
left:
418+
self: SELECT (SelectStatement)
419+
exprs:
420+
- self: 1 (NumericLiteral)
421+
method:
422+
self: FULL (KeywordSequence)
423+
next_keyword:
424+
self: OUTER (Keyword)
425+
right:
426+
self: SELECT (SelectStatement)
427+
exprs:
428+
- self: 2 (NumericLiteral)
429+
",
430+
0,
431+
)),
432+
Box::new(SuccessTestCase::new(
433+
"\
434+
SELECT 1 UNION ALL CORRESPONDING SELECT 2
435+
",
436+
"\
437+
self: UNION (SetOperator)
438+
corresponding:
439+
self: CORRESPONDING (Keyword)
440+
distinct_or_all:
441+
self: ALL (Keyword)
442+
left:
443+
self: SELECT (SelectStatement)
444+
exprs:
445+
- self: 1 (NumericLiteral)
446+
right:
447+
self: SELECT (SelectStatement)
448+
exprs:
449+
- self: 2 (NumericLiteral)
450+
",
451+
0,
452+
)),
453+
Box::new(SuccessTestCase::new(
454+
"\
455+
SELECT 1 UNION ALL STRICT CORRESPONDING SELECT 2
456+
",
457+
"\
458+
self: UNION (SetOperator)
459+
corresponding:
460+
self: STRICT (KeywordSequence)
461+
next_keyword:
462+
self: CORRESPONDING (Keyword)
463+
distinct_or_all:
464+
self: ALL (Keyword)
465+
left:
466+
self: SELECT (SelectStatement)
467+
exprs:
468+
- self: 1 (NumericLiteral)
469+
right:
470+
self: SELECT (SelectStatement)
471+
exprs:
472+
- self: 2 (NumericLiteral)
473+
",
474+
0,
475+
)),
476+
Box::new(SuccessTestCase::new(
477+
"\
478+
SELECT 1 UNION ALL STRICT CORRESPONDING BY (foo, bar) SELECT 2
479+
",
480+
"\
481+
self: UNION (SetOperator)
482+
corresponding:
483+
self: STRICT (KeywordSequence)
484+
next_keyword:
485+
self: CORRESPONDING (KeywordSequence)
486+
next_keyword:
487+
self: BY (KeywordWithExpr)
488+
expr:
489+
self: ( (GroupedExprs)
490+
exprs:
491+
- self: foo (Identifier)
492+
comma:
493+
self: , (Symbol)
494+
- self: bar (Identifier)
495+
rparen:
496+
self: ) (Symbol)
497+
distinct_or_all:
498+
self: ALL (Keyword)
499+
left:
500+
self: SELECT (SelectStatement)
501+
exprs:
502+
- self: 1 (NumericLiteral)
503+
right:
504+
self: SELECT (SelectStatement)
505+
exprs:
506+
- self: 2 (NumericLiteral)
507+
",
508+
0,
509+
)),
510+
Box::new(SuccessTestCase::new(
511+
"\
512+
SELECT 1 UNION ALL CORRESPONDING BY (foo) SELECT 2
513+
",
514+
"\
515+
self: UNION (SetOperator)
516+
corresponding:
517+
self: CORRESPONDING (KeywordSequence)
518+
next_keyword:
519+
self: BY (KeywordWithExpr)
520+
expr:
521+
self: ( (GroupedExprs)
522+
exprs:
523+
- self: foo (Identifier)
524+
rparen:
525+
self: ) (Symbol)
526+
distinct_or_all:
527+
self: ALL (Keyword)
528+
left:
529+
self: SELECT (SelectStatement)
530+
exprs:
531+
- self: 1 (NumericLiteral)
532+
right:
533+
self: SELECT (SelectStatement)
534+
exprs:
535+
- self: 2 (NumericLiteral)
369536
",
370537
0,
371538
)),

src/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,8 @@ export type SetOperator = XXXStatement & {
12391239
node_type: "SetOperator";
12401240
children: {
12411241
with?: { Node: WithClause };
1242+
by?: NodeChild;
1243+
corresponding?: NodeChild;
12421244
distinct_or_all: NodeChild;
12431245
left: { Node: SetOperator | SelectStatement | GroupedStatement };
12441246
right: { Node: SetOperator | SelectStatement | GroupedStatement };

0 commit comments

Comments
 (0)