Skip to content

Commit

Permalink
feat(grammar): Support recursive subquery factoring syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
felipebz committed May 25, 2024
1 parent 7c8f200 commit d335949
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2597,24 +2597,6 @@
"SELECT-12.sql": [
3
],
"SELECT-14.sql": [
3
],
"SELECT-15.sql": [
3
],
"SELECT-16.sql": [
3
],
"SELECT-17.sql": [
3
],
"SELECT-18.sql": [
3
],
"SELECT-19.sql": [
3
],
"SELECT-23.sql": [
2
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,30 @@
5,
5
],
"SELECT-14.sql": [
10,
10
],
"SELECT-15.sql": [
12,
12
],
"SELECT-16.sql": [
10,
10
],
"SELECT-17.sql": [
11,
11
],
"SELECT-18.sql": [
11,
11
],
"SELECT-19.sql": [
10,
10
],
"SELECT-34.sql": [
6,
6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ enum class DmlGrammar : GrammarRuleKey {
CONNECT_BY_CLAUSE,
START_WITH_CLAUSE,
HIERARCHICAL_QUERY_CLAUSE,
WITH_CLAUSE,
SUBQUERY_FACTORING_CLAUSE,
SEARCH_CLAUSE,
CYCLE_CLAUSE,
RETURNING_INTO_CLAUSE,
QUERY_BLOCK,
SELECT_EXPRESSION,
Expand Down Expand Up @@ -238,9 +241,30 @@ enum class DmlGrammar : GrammarRuleKey {
b.sequence(CONNECT_BY_CLAUSE, b.optional(START_WITH_CLAUSE)),
b.sequence(START_WITH_CLAUSE, CONNECT_BY_CLAUSE)))

b.rule(WITH_CLAUSE).define(
WITH,
b.oneOrMore(SUBQUERY_FACTORING_CLAUSE, b.optional(COMMA))
)

b.rule(SUBQUERY_FACTORING_CLAUSE).define(
WITH,
b.oneOrMore(IDENTIFIER_NAME, AS, LPARENTHESIS, SELECT_EXPRESSION, RPARENTHESIS, b.optional(COMMA)))
IDENTIFIER_NAME,
b.optional(LPARENTHESIS, IDENTIFIER_NAME, b.zeroOrMore(COMMA, IDENTIFIER_NAME), RPARENTHESIS),
AS,
LPARENTHESIS, SELECT_EXPRESSION, RPARENTHESIS,
b.optional(SEARCH_CLAUSE),
b.optional(CYCLE_CLAUSE)
)

b.rule(SEARCH_CLAUSE).define(
SEARCH, b.firstOf(BREADTH, DEPTH),
FIRST, BY, ORDER_BY_ITEM, b.zeroOrMore(COMMA, ORDER_BY_ITEM),
SET, IDENTIFIER_NAME
)

b.rule(CYCLE_CLAUSE).define(
CYCLE, IDENTIFIER_NAME, b.zeroOrMore(COMMA, IDENTIFIER_NAME),
SET, IDENTIFIER_NAME, TO, EXPRESSION, DEFAULT, EXPRESSION
)

b.rule(QUERY_BLOCK).define(
b.firstOf(
Expand All @@ -257,7 +281,7 @@ enum class DmlGrammar : GrammarRuleKey {
b.sequence(LPARENTHESIS, SELECT_EXPRESSION, RPARENTHESIS)))

b.rule(SELECT_EXPRESSION).define(
b.optional(SUBQUERY_FACTORING_CLAUSE),
b.optional(WITH_CLAUSE),
QUERY_BLOCK,
b.zeroOrMore(b.firstOf(MINUS_KEYWORD, INTERSECT, UNION, EXCEPT), b.optional(ALL), QUERY_BLOCK),
b.optional(b.firstOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ enum class PlSqlKeyword(override val value: String, val isReserved: Boolean = fa
BOOLEAN("boolean"),
BOTH("both"),
BUFFER_POOL("buffer_pool"),
BREADTH("breadth"),
BULK("bulk"),
BULK_ROWCOUNT("bulk_rowcount"),
BYTE("byte"),
Expand Down Expand Up @@ -191,6 +192,7 @@ enum class PlSqlKeyword(override val value: String, val isReserved: Boolean = fa
DELEGATE("delegate"),
DELETE("delete"),
DENSE_RANK("dense_rank"),
DEPTH("depth"),
DEPRECATE("deprecate"),
DETERMINISTIC("deterministic"),
DIRECTORY("directory"),
Expand Down Expand Up @@ -413,6 +415,7 @@ enum class PlSqlKeyword(override val value: String, val isReserved: Boolean = fa
ROWTYPE("rowtype"),
SAVE("save"),
SAVEPOINT("savepoint"),
SEARCH("search"),
SCHEMA("schema"),
SCHEMACHECK("schemacheck"),
SECOND("second"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@
*/
package org.sonar.plugins.plsqlopen.api.sql

import com.felipebz.flr.tests.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.sonar.plugins.plsqlopen.api.DmlGrammar
import org.sonar.plugins.plsqlopen.api.RuleTest
import com.felipebz.flr.tests.Assertions.assertThat

class SubqueryFactoringClauseTest : RuleTest() {
class WithClauseTest : RuleTest() {

@BeforeEach
fun init() {
setRootRule(DmlGrammar.SUBQUERY_FACTORING_CLAUSE)
setRootRule(DmlGrammar.WITH_CLAUSE)
}

@Test
Expand All @@ -42,4 +42,19 @@ class SubqueryFactoringClauseTest : RuleTest() {
assertThat(p).matches("with q as (select 1 from dual), q2 as (select 1 from dual)")
}

@Test
fun matchesRecursiveSimple() {
assertThat(p).matches("with q(id, parent) as (select 1 from dual)")
}

@Test
fun matchesRecursiveWithSearch() {
assertThat(p).matches("with q(id, parent) as (select 1 from dual) search depth first by a set order1")
}

@Test
fun matchesRecursiveWithSearchAndCycle() {
assertThat(p).matches("with q(id, parent) as (select 1 from dual) search depth first by a set order1 cycle id set cycle to 1 default 0")
}

}

0 comments on commit d335949

Please sign in to comment.