Skip to content

Commit 3dc2b5e

Browse files
authored
Merge pull request #1592 from johnedquinn/v0_14_9_update_dml
Add dml update to partiql_logical pig domain and improve DML modeling
2 parents 8634620 + 870d159 commit 3dc2b5e

19 files changed

+830
-1358
lines changed

CHANGELOG.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,20 @@ Thank you to all who have contributed!
2525

2626
## [0.14.9]
2727

28-
### Added
29-
3028
### Changed
3129
- With full, closed schema, the planner will now give a plan-time warning when it can prove an exclude path will never
3230
exclude a value (relevant issue -- https://github.com/partiql/partiql-lang/issues/91).
3331

34-
### Deprecated
35-
36-
### Fixed
37-
38-
### Removed
39-
40-
### Security
32+
### Experimental Changes
33+
- **BREAKING**: For the _experimental_ `org.partiql.lang.domains` of `PartiqlLogical`, `PartiqlLogicalResolved`, and `PartiqlPhysical`,
34+
the modeling of DML has changed substantially. These changes, while considered breaking changes, are part of an
35+
experimental area of the PartiQL library and thus do not mandate a major-version bump of this library. Consumers
36+
of these experimental APIs should be wary of these changes.
4137

4238
### Contributors
4339
- @alancai98
40+
- @dlurton
41+
- @johnedquinn
4442

4543
## [0.14.8]
4644

partiql-ast/src/main/pig/partiql.ion

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -802,55 +802,83 @@ may then be further optimized by selecting better implementations of each operat
802802
)
803803
)
804804

805+
(with statement
806+
(exclude dml)
807+
(include
808+
// An `INSERT` DML operation, which is fundamentally different from UPDATE and DELETE
809+
// because it lacks a FROM and WHERE clause while also including an ON CONFLICT clause.
810+
//
811+
// Models: INSERT INTO <dml_target> [AS <target_alias>] <rows_to_insert> [<on-conflict>]
812+
(dml_insert
813+
// The target is an expression indicates the table whose data is to be manipulated.
814+
// With current PartiQL Parser `SqlParser`, this can be an identifier or a simplified path expression
815+
// consisting of only literal path steps (and with no wildcard or unpivot operators).
816+
// Note: partiql_ast uses the `expr` sum type for this, which is too broad. We're not
817+
// changing that at this time because `partiql_ast` is established public API, but we can
818+
// use dml_target instead which has the properly narrowed domain.
819+
(target dml_target)
820+
(target_alias var_decl)
821+
(rows_to_insert expr)
822+
(on_conflict (? on_conflict))
823+
)
824+
825+
// Models: UPDATE <dml_target> [AS <target_alias>] SET <assignments> [WHERE <where>]
826+
(dml_update
827+
(target dml_target)
828+
(target_alias var_decl)
829+
(assignments (* set_assignment 0))
830+
(where (? expr))
831+
)
832+
833+
// Models DELETE <from>
834+
(dml_delete (from bexpr)) // note: the bexpr includes filters, etc.
835+
)
836+
)
837+
805838
(include
806-
// Indicates kind of DML operation.
807-
(sum dml_operation
808-
(dml_insert target_alias::var_decl)
809-
(dml_delete)
810-
811-
// Represents the REPLACE statement as well as INSERT ... ON CONFLICT DO REPLACE ...
812-
// [target-alias]: represents the alias for the table name. See the following syntactical example:
813-
// `INSERT INTO Table1 AS <alias> << { 'id': 1, 'name': 'Arash' } >> ON CONFLICT DO REPLACE ...`
814-
// [condition]: represents the condition by which a row should be replaced. See the following syntactical example:
815-
// `INSERT INTO x << {'id': 1, 'name': 'John'}} >> ON CONFLICT DO REPLACE EXCLUDED WHERE <condition>`
816-
// [row_alias]: represents the alias given to the rows meant to be inserted/replaced. It is made optional
817-
// since dml_replace is currently shared by REPLACE (which does not allow the aliasing of rows) and
818-
// INSERT ... ON CONFLICT DO REPLACE ... (which aliases the rows as "EXCLUDED" for use within the [condition]).
819-
(dml_replace target_alias::var_decl condition::(? expr) row_alias::(? var_decl))
820-
821-
// Represents the UPSERT statement as well as INSERT ... ON CONFLICT DO UPDATE ...
822-
// [target-alias]: represents the alias for the table name. See the following syntactical example:
823-
// `INSERT INTO Table1 AS <alias> << { 'id': 1, 'name': 'Arash' } >> ON CONFLICT DO UPDATE ...`
824-
// [condition]: represents the condition by which a row should be replaced. See the following syntactical example:
825-
// `INSERT INTO x << {'id': 1, 'name': 'John'}} >> ON CONFLICT DO UPDATE EXCLUDED WHERE <condition>`
826-
// [row_alias]: represents the alias given to the rows meant to be inserted/updated. It is made optional
827-
// since dml_update is currently shared by UPSERT (which does not allow the aliasing of rows) and
828-
// INSERT ... ON CONFLICT DO UPDATE ... (which aliases the rows as "EXCLUDED" for use within the [condition]).
829-
(dml_update target_alias::var_decl condition::(? expr) row_alias::(? var_decl))
839+
// represents simple paths, i.e. suitable for the left side of an `=` operator within a `SET` clause.
840+
// Example `a_field.nested_field[42]`
841+
(record simple_path
842+
// The first element, `a_field` in the example above.
843+
(root identifier)
844+
// The subsequent elements, `nested_field` and `[42]` in the example above.
845+
(steps (* simple_path_step 0))
846+
)
847+
(sum simple_path_step
848+
// for bracket paths steps, i.e. `[42]` in the simple_path example above.
849+
(sps_index (index int))
850+
// for symbols, i.e. `nested_field` in the simple_path example above.
851+
(sps_identifier (identifier identifier))
830852
)
831-
)
832853

833-
// Redefine statement.dml to be a simpler subset of the full DML functionality expressed with PartiQL's DML
834-
// syntax. Full functionality is out of scope for now. This is factored minimally to support
835-
// `INSERT INTO` and `DELETE FROM ... [WHERE <predicate>]` but this may need refactoring when
836-
// `FROM ... UPDATE` and `UPDATE` is supported later.
837-
(with statement
838-
(exclude dml)
839-
(include
840-
// A DML operation, such as `INSERT`, `UPDATE` or `DELETE`
841-
(dml
842-
// The target is an expression that is indicates the table whose data is to be manipulated.
843-
// With current PartiQL Parser `SqlParser`, this can be an identifier or a simplified path expression
844-
// consisting of only literal path steps (and with no wildcard or unpivot operators).
845-
// Note: partiql_ast uses the `expr` sum type for this, which is too broad. We're not
846-
// changing that at this time because `partiql_ast` is established public API.
847-
target::identifier
848-
operation::dml_operation
849-
rows::expr
850-
)
854+
// The "target" of a DML operation, i.e. the table targeted for manipulation with INSERT, UPDATE, etc.
855+
// This is a discrete type so it can be permuted in later domains to affect every use.
856+
(record dml_target (identifier identifier))
857+
858+
// An assignment within a SET clause.
859+
(record set_assignment
860+
// The target, left of `=`
861+
(set_target simple_path)
862+
// The new value for the target, right of `=`
863+
(value expr)
851864
)
865+
866+
// INSERT's ON CONFLICT Clause
867+
(record on_conflict
868+
(excluded_alias var_decl)
869+
(condition (? expr))
870+
(action on_conflict_action)
871+
)
872+
873+
(sum on_conflict_action
874+
(do_update)
875+
(do_replace)
876+
)
877+
852878
)
853879

880+
881+
854882
// Nodes excluded below this line will eventually have a representation in the logical algebra, but not
855883
// initially.
856884

@@ -934,11 +962,9 @@ may then be further optimized by selecting better implementations of each operat
934962
)
935963
)
936964

937-
// Replace statement.dml.target with statement.dml.uniqueId (the "resolved" corollary).
938-
(with statement
939-
(exclude dml)
940-
(include (dml uniqueId::symbol operation::dml_operation rows::expr))
941-
)
965+
// Replace statement.dml.uniqueId (the "resolved" corollary).
966+
(exclude dml_target)
967+
(include (record dml_target (uniqueId symbol)))
942968
)
943969
)
944970

partiql-coverage/src/test/kotlin/org/partiql/coverage/api/impl/PartiQLTestExtensionTest.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import org.partiql.coverage.api.PartiQLTest
3131
import org.partiql.coverage.api.PartiQLTestCase
3232
import org.partiql.coverage.api.PartiQLTestProvider
3333
import org.partiql.lang.CompilerPipeline
34-
import org.partiql.lang.eval.EvaluationSession
3534
import org.partiql.lang.eval.PartiQLResult
3635
import java.lang.reflect.AnnotatedElement
3736
import java.lang.reflect.Method
@@ -76,19 +75,9 @@ class PartiQLTestExtensionTest {
7675
fun test2(tc: PartiQLTestCase, result: PartiQLResult.Value) {
7776
}
7877

79-
@Disabled
80-
@PartiQLTest(provider = MockProvider::class)
81-
@JvmName("test3")
82-
@Suppress("UNUSED")
83-
fun test3(tc: ValidTestCase, result: PartiQLResult.Delete) {
84-
}
85-
86-
class ValidTestCase(override val session: EvaluationSession) : PartiQLTestCase
87-
8878
override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> = listOf(
8979
AbstractExtensionContext(ValidSignaturesProvider::class.java, "test1", PartiQLTestCase::class.java, PartiQLResult::class.java),
9080
AbstractExtensionContext(ValidSignaturesProvider::class.java, "test2", PartiQLTestCase::class.java, PartiQLResult.Value::class.java),
91-
AbstractExtensionContext(ValidSignaturesProvider::class.java, "test3", ValidTestCase::class.java, PartiQLResult.Delete::class.java),
9281
).map { Arguments.of(it) }.stream()
9382
}
9483

partiql-lang/src/main/kotlin/org/partiql/lang/compiler/PartiQLCompilerAsyncDefault.kt

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ internal class PartiQLCompilerAsyncDefault(
6363

6464
override suspend fun compile(statement: PartiqlPhysical.Plan): PartiQLStatementAsync {
6565
return when (val stmt = statement.stmt) {
66-
is PartiqlPhysical.Statement.Dml -> compileDml(stmt, statement.locals.size)
66+
is PartiqlPhysical.Statement.DmlDelete,
67+
is PartiqlPhysical.Statement.DmlInsert,
68+
is PartiqlPhysical.Statement.DmlUpdate -> TODO("DML compilation not supported.")
6769
is PartiqlPhysical.Statement.Exec,
6870
is PartiqlPhysical.Statement.Query -> {
6971
val expression = exprConverter.compile(statement)
@@ -75,7 +77,9 @@ internal class PartiQLCompilerAsyncDefault(
7577

7678
override suspend fun compile(statement: PartiqlPhysical.Plan, details: PartiQLPlanner.PlanningDetails): PartiQLStatementAsync {
7779
return when (val stmt = statement.stmt) {
78-
is PartiqlPhysical.Statement.Dml -> compileDml(stmt, statement.locals.size)
80+
is PartiqlPhysical.Statement.DmlDelete,
81+
is PartiqlPhysical.Statement.DmlInsert,
82+
is PartiqlPhysical.Statement.DmlUpdate -> TODO("DML compilation not supported.")
7983
is PartiqlPhysical.Statement.Exec,
8084
is PartiqlPhysical.Statement.Query -> compile(statement)
8185
is PartiqlPhysical.Statement.Explain -> PartiQLStatementAsync { compileExplain(stmt, details) }
@@ -93,18 +97,6 @@ internal class PartiQLCompilerAsyncDefault(
9397
PHYSICAL_TRANSFORMED
9498
}
9599

96-
private suspend fun compileDml(dml: PartiqlPhysical.Statement.Dml, localsSize: Int): PartiQLStatementAsync {
97-
val rows = exprConverter.compile(dml.rows, localsSize)
98-
return PartiQLStatementAsync { session ->
99-
when (dml.operation) {
100-
is PartiqlPhysical.DmlOperation.DmlReplace -> PartiQLResult.Replace(dml.uniqueId.text, (rows.eval(session) as PartiQLResult.Value).value)
101-
is PartiqlPhysical.DmlOperation.DmlInsert -> PartiQLResult.Insert(dml.uniqueId.text, (rows.eval(session) as PartiQLResult.Value).value)
102-
is PartiqlPhysical.DmlOperation.DmlDelete -> PartiQLResult.Delete(dml.uniqueId.text, (rows.eval(session) as PartiQLResult.Value).value)
103-
is PartiqlPhysical.DmlOperation.DmlUpdate -> TODO("DML Update compilation not supported yet.")
104-
}
105-
}
106-
}
107-
108100
private fun compileExplain(statement: PartiqlPhysical.Statement.Explain, details: PartiQLPlanner.PlanningDetails): PartiQLResult.Explain.Domain {
109101
return when (val target = statement.target) {
110102
is PartiqlPhysical.ExplainTarget.Domain -> compileExplainDomain(target, details)

partiql-lang/src/main/kotlin/org/partiql/lang/compiler/PartiQLCompilerDefault.kt

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ internal class PartiQLCompilerDefault(
6565

6666
override fun compile(statement: PartiqlPhysical.Plan): PartiQLStatement {
6767
return when (val stmt = statement.stmt) {
68-
is PartiqlPhysical.Statement.Dml -> compileDml(stmt, statement.locals.size)
68+
is PartiqlPhysical.Statement.DmlDelete,
69+
is PartiqlPhysical.Statement.DmlInsert,
70+
is PartiqlPhysical.Statement.DmlUpdate -> TODO("DML compilation not supported.")
6971
is PartiqlPhysical.Statement.Exec,
7072
is PartiqlPhysical.Statement.Query -> {
7173
val expression = exprConverter.compile(statement)
@@ -77,7 +79,9 @@ internal class PartiQLCompilerDefault(
7779

7880
override fun compile(statement: PartiqlPhysical.Plan, details: PartiQLPlanner.PlanningDetails): PartiQLStatement {
7981
return when (val stmt = statement.stmt) {
80-
is PartiqlPhysical.Statement.Dml -> compileDml(stmt, statement.locals.size)
82+
is PartiqlPhysical.Statement.DmlDelete,
83+
is PartiqlPhysical.Statement.DmlInsert,
84+
is PartiqlPhysical.Statement.DmlUpdate -> TODO("DML compilation not supported.")
8185
is PartiqlPhysical.Statement.Exec,
8286
is PartiqlPhysical.Statement.Query -> compile(statement)
8387
is PartiqlPhysical.Statement.Explain -> PartiQLStatement { compileExplain(stmt, details) }
@@ -95,18 +99,6 @@ internal class PartiQLCompilerDefault(
9599
PHYSICAL_TRANSFORMED
96100
}
97101

98-
private fun compileDml(dml: PartiqlPhysical.Statement.Dml, localsSize: Int): PartiQLStatement {
99-
val rows = exprConverter.compile(dml.rows, localsSize)
100-
return PartiQLStatement { session ->
101-
when (dml.operation) {
102-
is PartiqlPhysical.DmlOperation.DmlReplace -> PartiQLResult.Replace(dml.uniqueId.text, rows.eval(session))
103-
is PartiqlPhysical.DmlOperation.DmlInsert -> PartiQLResult.Insert(dml.uniqueId.text, rows.eval(session))
104-
is PartiqlPhysical.DmlOperation.DmlDelete -> PartiQLResult.Delete(dml.uniqueId.text, rows.eval(session))
105-
is PartiqlPhysical.DmlOperation.DmlUpdate -> TODO("DML Update compilation not supported yet.")
106-
}
107-
}
108-
}
109-
110102
private fun compileExplain(statement: PartiqlPhysical.Statement.Explain, details: PartiQLPlanner.PlanningDetails): PartiQLResult.Explain.Domain {
111103
return when (val target = statement.target) {
112104
is PartiqlPhysical.ExplainTarget.Domain -> compileExplainDomain(target, details)

partiql-lang/src/main/kotlin/org/partiql/lang/eval/physical/PhysicalPlanCompilerAsyncImpl.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ internal class PhysicalPlanCompilerAsyncImpl(
226226
return when (ast) {
227227
is PartiqlPhysical.Statement.Query -> compileAstExpr(ast.expr)
228228
is PartiqlPhysical.Statement.Exec -> compileExec(ast)
229-
is PartiqlPhysical.Statement.Dml,
229+
is PartiqlPhysical.Statement.DmlDelete,
230+
is PartiqlPhysical.Statement.DmlInsert,
231+
is PartiqlPhysical.Statement.DmlUpdate -> TODO("DML compilation not supported.")
230232
is PartiqlPhysical.Statement.Explain -> {
231233
val value = ExprValue.newBoolean(true)
232234
thunkFactory.thunkEnvAsync(emptyMetaContainer()) { value }

partiql-lang/src/main/kotlin/org/partiql/lang/eval/physical/PhysicalPlanCompilerImpl.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ internal class PhysicalPlanCompilerImpl(
241241
return when (ast) {
242242
is PartiqlPhysical.Statement.Query -> compileAstExpr(ast.expr)
243243
is PartiqlPhysical.Statement.Exec -> compileExec(ast)
244-
is PartiqlPhysical.Statement.Dml,
244+
is PartiqlPhysical.Statement.DmlDelete,
245+
is PartiqlPhysical.Statement.DmlInsert,
246+
is PartiqlPhysical.Statement.DmlUpdate -> TODO("DML compilation not supported.")
245247
is PartiqlPhysical.Statement.Explain -> {
246248
val value = ExprValue.newBoolean(true)
247249
thunkFactory.thunkEnv(emptyMetaContainer()) { value }

0 commit comments

Comments
 (0)