Skip to content

Commit

Permalink
Adds support for EXCLUDE in the SqlDialect
Browse files Browse the repository at this point in the history
  • Loading branch information
johnedquinn committed Dec 7, 2023
1 parent f8f6b2a commit 8a37a9a
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Thank you to all who have contributed!
- **EXPERIMENTAL** Evaluation of `EXCLUDE` in the `EvaluatingCompiler`
- This is currently marked as experimental until the RFC is approved https://github.com/partiql/partiql-lang/issues/27
- This will be added to the `PhysicalPlanCompiler` in an upcoming release
- **EXPERIMENTAL**: Adds support for EXCLUDE in the default SqlDialect.

### Changed
- StaticTypeInferencer and PlanTyper will not raise an error when an expression is inferred to `NULL` or `unionOf(NULL, MISSING)`. In these cases the StaticTypeInferencer and PlanTyper will still raise the Problem Code `ExpressionAlwaysReturnsNullOrMissing` but the severity of the problem has been changed to warning. In the case an expression always returns `MISSING`, problem code `ExpressionAlwaysReturnsMissing` will be raised, which will have problem severity of error.
Expand Down
35 changes: 35 additions & 0 deletions partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.partiql.ast.sql

import org.partiql.ast.AstNode
import org.partiql.ast.Exclude
import org.partiql.ast.Expr
import org.partiql.ast.From
import org.partiql.ast.GroupBy
Expand Down Expand Up @@ -82,6 +83,38 @@ public abstract class SqlDialect : AstBaseVisitor<SqlBlock, SqlBlock>() {
return head concat r(path)
}

override fun visitExclude(node: Exclude, head: SqlBlock): SqlBlock {
var h = head
h = h concat " EXCLUDE "
h = h concat list(start = null, end = null) { node.exprs }
return h
}

override fun visitExcludeExcludeExpr(node: Exclude.ExcludeExpr, head: SqlBlock): SqlBlock {
var h = head
h = h concat visitIdentifierSymbol(node.root, SqlBlock.Nil)
h = h concat list(delimiter = null, start = null, end = null) { node.steps }
return h
}

override fun visitExcludeStepExcludeCollectionIndex(node: Exclude.Step.ExcludeCollectionIndex, head: SqlBlock): SqlBlock {
return head concat r("[${node.index}]")
}

override fun visitExcludeStepExcludeTupleWildcard(node: Exclude.Step.ExcludeTupleWildcard, head: SqlBlock): SqlBlock {
return head concat r(".*")
}

override fun visitExcludeStepExcludeTupleAttr(node: Exclude.Step.ExcludeTupleAttr, head: SqlBlock): SqlBlock {
var h = head concat r(".")
h = h concat visitIdentifierSymbol(node.symbol, SqlBlock.Nil)
return h
}

override fun visitExcludeStepExcludeCollectionWildcard(node: Exclude.Step.ExcludeCollectionWildcard, head: SqlBlock): SqlBlock {
return head concat r("[*]")
}

// cannot write path step outside the context of a path as we don't want it to reflow
override fun visitPathStep(node: Path.Step, head: SqlBlock) = error("path step cannot be written directly")

Expand Down Expand Up @@ -550,6 +583,8 @@ public abstract class SqlDialect : AstBaseVisitor<SqlBlock, SqlBlock>() {
var h = head
// SELECT
h = visit(node.select, h)
// EXCLUDE
h = node.exclude?.let { visit(it, h) } ?: h
// FROM
h = visit(node.from, h concat r(" FROM "))
// LET
Expand Down
93 changes: 93 additions & 0 deletions partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ class SqlDialectTest {
@Execution(ExecutionMode.CONCURRENT)
fun testSelectClause(case: Case) = case.assert()

@ParameterizedTest(name = "EXCLUDE Clause #{index}")
@MethodSource("excludeClauseCases")
@Execution(ExecutionMode.CONCURRENT)
fun testExcludeClause(case: Case) = case.assert()

@ParameterizedTest(name = "FROM Clause #{index}")
@MethodSource("fromClauseCases")
@Execution(ExecutionMode.CONCURRENT)
Expand Down Expand Up @@ -1058,6 +1063,94 @@ class SqlDialectTest {
},
)

@JvmStatic
fun excludeClauseCases() = listOf(
expect("SELECT a EXCLUDE t.a FROM T") {
exprSFW {
select = select("a")
from = fromValue {
expr = v("T")
type = From.Value.Type.SCAN
}
exclude = exclude {
exprs += excludeExcludeExpr {
root = id("t", Identifier.CaseSensitivity.INSENSITIVE)
steps += excludeStepExcludeTupleAttr {
symbol = id("a", Identifier.CaseSensitivity.INSENSITIVE)
}
}
}
}
},
expect("SELECT a EXCLUDE a.b, c.d, e.f, g.h FROM T") {
exprSFW {
select = select("a")
from = fromValue {
expr = v("T")
type = From.Value.Type.SCAN
}
exclude = exclude {
exprs += excludeExcludeExpr {
root = id("a", Identifier.CaseSensitivity.INSENSITIVE)
steps += insensitiveExcludeTupleAttr("b")
}
exprs += excludeExcludeExpr {
root = id("c", Identifier.CaseSensitivity.INSENSITIVE)
steps += insensitiveExcludeTupleAttr("d")
}
exprs += excludeExcludeExpr {
root = id("e", Identifier.CaseSensitivity.INSENSITIVE)
steps += insensitiveExcludeTupleAttr("f")
}
exprs += excludeExcludeExpr {
root = id("g", Identifier.CaseSensitivity.INSENSITIVE)
steps += insensitiveExcludeTupleAttr("h")
}
}
}
},
expect("SELECT a EXCLUDE t.a.\"b\".*[*].c, \"s\"[0].d.\"e\"[*].f.* FROM T") {
exprSFW {
select = select("a")
from = fromValue {
expr = v("T")
type = From.Value.Type.SCAN
}
exclude = exclude {
exprs += excludeExcludeExpr {
root = id("t", Identifier.CaseSensitivity.INSENSITIVE)
steps += mutableListOf(
insensitiveExcludeTupleAttr("a"),
sensitiveExcludeTupleAttr("b"),
excludeStepExcludeTupleWildcard(),
excludeStepExcludeCollectionWildcard(),
insensitiveExcludeTupleAttr("c"),
)
}
exprs += excludeExcludeExpr {
root = id("s", Identifier.CaseSensitivity.SENSITIVE)
steps += mutableListOf(
excludeStepExcludeCollectionIndex(0),
insensitiveExcludeTupleAttr("d"),
sensitiveExcludeTupleAttr("e"),
excludeStepExcludeCollectionWildcard(),
insensitiveExcludeTupleAttr("f"),
excludeStepExcludeTupleWildcard(),
)
}
}
}
},
)

private fun AstBuilder.insensitiveExcludeTupleAttr(str: String) = excludeStepExcludeTupleAttr {
symbol = id(str, Identifier.CaseSensitivity.INSENSITIVE)
}

private fun AstBuilder.sensitiveExcludeTupleAttr(str: String) = excludeStepExcludeTupleAttr {
symbol = id(str, Identifier.CaseSensitivity.SENSITIVE)
}

@JvmStatic
fun fromClauseCases() = listOf(
expect("SELECT a FROM T") {
Expand Down

0 comments on commit 8a37a9a

Please sign in to comment.