Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1 roll back ddl #1525

Merged
merged 6 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
964 changes: 342 additions & 622 deletions partiql-ast/api/partiql-ast.api

Large diffs are not rendered by default.

76 changes: 26 additions & 50 deletions partiql-ast/src/main/kotlin/org/partiql/ast/helpers/ToLegacyAst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import com.amazon.ionelement.api.ionString
import com.amazon.ionelement.api.ionSymbol
import com.amazon.ionelement.api.metaContainerOf
import org.partiql.ast.AstNode
import org.partiql.ast.Constraint
import org.partiql.ast.DatetimeField
import org.partiql.ast.DdlOp
import org.partiql.ast.Exclude
import org.partiql.ast.Expr
import org.partiql.ast.From
Expand Down Expand Up @@ -125,29 +123,24 @@ private class AstTranslator(val metas: Map<String, MetaContainer>) : AstBaseVisi
domain(statement, type, format, metas)
}

override fun visitStatementDDL(node: Statement.DDL, ctx: Ctx) = when (val op = node.op) {
is DdlOp.CreateIndex -> visitDdlOpCreateIndex(op, ctx)
is DdlOp.CreateTable -> visitDdlOpCreateTable(op, ctx)
is DdlOp.DropIndex -> visitDdlOpDropIndex(op, ctx)
is DdlOp.DropTable -> visitDdlOpDropTable(op, ctx)
}
override fun visitStatementDDL(node: Statement.DDL, ctx: Ctx) = super.visit(node, ctx) as PartiqlAst.Statement.Ddl

override fun visitDdlOpCreateTable(node: DdlOp.CreateTable, ctx: Ctx) = translate(node) { metas ->
override fun visitStatementDDLCreateTable(
node: Statement.DDL.CreateTable,
ctx: Ctx,
) = translate(node) { metas ->
if (node.name !is Identifier.Symbol) {
error("The legacy AST does not support qualified identifiers as table names")
}
val tableName = node.name.symbol
val tableName = (node.name as Identifier.Symbol).symbol
val def = node.definition?.let { visitTableDefinition(it, ctx) }
if (node.partitionBy != null) {
error("The legacy AST does not support Partition BY in create Table")
}
if (node.tableProperties.isNotEmpty()) {
error("The legacy AST does not support TBLProperties in create Table")
}
ddl(createTable(tableName, def), metas)
}

override fun visitDdlOpCreateIndex(node: DdlOp.CreateIndex, ctx: Ctx) = translate(node) { metas ->
override fun visitStatementDDLCreateIndex(
node: Statement.DDL.CreateIndex,
ctx: Ctx,
) = translate(node) { metas ->
if (node.index != null) {
error("The legacy AST does not support index names")
}
Expand All @@ -159,7 +152,7 @@ private class AstTranslator(val metas: Map<String, MetaContainer>) : AstBaseVisi
ddl(createIndex(tableName, fields), metas)
}

override fun visitDdlOpDropTable(node: DdlOp.DropTable, ctx: Ctx) = translate(node) { metas ->
override fun visitStatementDDLDropTable(node: Statement.DDL.DropTable, ctx: Ctx) = translate(node) { metas ->
if (node.table !is Identifier.Symbol) {
error("The legacy AST does not support qualified identifiers as table names")
}
Expand All @@ -168,7 +161,7 @@ private class AstTranslator(val metas: Map<String, MetaContainer>) : AstBaseVisi
ddl(dropTable(tableName), metas)
}

override fun visitDdlOpDropIndex(node: DdlOp.DropIndex, ctx: Ctx) = translate(node) { metas ->
override fun visitStatementDDLDropIndex(node: Statement.DDL.DropIndex, ctx: Ctx) = translate(node) { metas ->
if (node.index !is Identifier.Symbol) {
error("The legacy AST does not support qualified identifiers as index names")
}
Expand All @@ -183,34 +176,28 @@ private class AstTranslator(val metas: Map<String, MetaContainer>) : AstBaseVisi
}

override fun visitTableDefinition(node: TableDefinition, ctx: Ctx) = translate(node) { metas ->
val parts = node.attributes.translate<PartiqlAst.TableDefPart>(ctx)
if (node.constraints.isNotEmpty()) {
error("The legacy AST does not support table level constraint declaration")
}
val parts = node.columns.translate<PartiqlAst.TableDefPart>(ctx)
tableDef(parts, metas)
}

override fun visitTableDefinitionAttribute(node: TableDefinition.Attribute, ctx: Ctx) = translate(node) { metas ->
// Legacy AST treat table name as a case-sensitive string
val name = node.name.symbol
override fun visitTableDefinitionColumn(node: TableDefinition.Column, ctx: Ctx) = translate(node) { metas ->
val name = node.name
val type = visitType(node.type, ctx)
val constraints = node.constraints.translate<PartiqlAst.ColumnConstraint>(ctx)
if (node.isOptional) {
error("The legacy AST does not support optional field declaration")
}
if (node.comment != null) {
error("The legacy AST does not support comment clause")
}
columnDeclaration(name, type, constraints, metas)
}

override fun visitConstraint(node: Constraint, ctx: Ctx) = translate(node) {
override fun visitTableDefinitionColumnConstraint(
node: TableDefinition.Column.Constraint,
ctx: Ctx,
) = translate(node) { metas ->
val name = node.name
val def = when (node.definition) {
is Constraint.Definition.Check -> throw IllegalArgumentException("PIG AST does not support CHECK (<expr>) constraint")
is Constraint.Definition.NotNull -> columnNotnull()
is Constraint.Definition.Nullable -> columnNull()
is Constraint.Definition.Unique -> throw IllegalArgumentException("PIG AST does not support Unique/Primary Key constraint")
val def = when (node.body) {
is TableDefinition.Column.Constraint.Body.Check -> {
throw IllegalArgumentException("PIG AST does not support CHECK (<expr>) constraint")
}
is TableDefinition.Column.Constraint.Body.NotNull -> columnNotnull()
is TableDefinition.Column.Constraint.Body.Nullable -> columnNull()
}
columnConstraint(name, def, metas)
}
Expand Down Expand Up @@ -1379,22 +1366,11 @@ private class AstTranslator(val metas: Map<String, MetaContainer>) : AstBaseVisi

override fun visitTypeList(node: Type.List, ctx: Ctx) = translate(node) { metas -> listType(metas) }

override fun visitTypeArray(node: Type.Array, ctx: Ctx) = translate(node) { metas ->
if (node.type != null) {
error("The legacy AST does not support element type declaration for list")
}
listType(metas)
}
override fun visitTypeSexp(node: Type.Sexp, ctx: Ctx) = translate(node) { metas -> sexpType(metas) }

override fun visitTypeTuple(node: Type.Tuple, ctx: Ctx) = translate(node) { metas -> tupleType(metas) }

override fun visitTypeStruct(node: Type.Struct, ctx: Ctx) = translate(node) { metas ->
if (node.fields.isNotEmpty()) {
error("The legacy AST does not support field declaration in struct type")
}
structType(metas)
}
override fun visitTypeStruct(node: Type.Struct, ctx: Ctx) = translate(node) { metas -> structType(metas) }

override fun visitTypeAny(node: Type.Any, ctx: Ctx) = translate(node) { metas -> anyType(metas) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,10 @@ internal abstract class InternalSqlDialect : AstBaseVisitor<InternalSqlBlock, In

override fun visitTypeList(node: Type.List, tail: InternalSqlBlock): InternalSqlBlock = tail concat "LIST"

// TODO: Support List Element
override fun visitTypeArray(node: Type.Array, tail: InternalSqlBlock): InternalSqlBlock = tail concat "ARRAY"
override fun visitTypeSexp(node: Type.Sexp, tail: InternalSqlBlock): InternalSqlBlock = tail concat "SEXP"

override fun visitTypeTuple(node: Type.Tuple, tail: InternalSqlBlock): InternalSqlBlock = tail concat "TUPLE"

// TODO: Support Struct Field
override fun visitTypeStruct(node: Type.Struct, tail: InternalSqlBlock): InternalSqlBlock = tail concat "STRUCT"

override fun visitTypeAny(node: Type.Any, tail: InternalSqlBlock): InternalSqlBlock = tail concat "ANY"
Expand Down
152 changes: 44 additions & 108 deletions partiql-ast/src/main/resources/partiql_ast.ion
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,32 @@ statement::[
],

// Data Definition Language
d_d_l::{
op: ddl_op
},
d_d_l::[

// CREATE TABLE <identifier> [<table_def>]
create_table::{
name: identifier,
definition: optional::table_definition,
},

// CREATE INDEX [<identifier>] ON <identifier> (<path> [, <path>]...)
create_index::{
index: optional::identifier,
table: identifier,
fields: list::[path],
},

// DROP TABLE <identifier>
drop_table::{
table: identifier,
},

// DROP INDEX <identifier> ON <identifier>
drop_index::{
index: identifier, // <identifier>[0]
table: identifier, // <identifier>[1]
},
],

// EXEC <symbol> [<expr>.*]
exec::{
Expand All @@ -128,38 +151,6 @@ statement::[
},
]

ddl_op::[
// CREATE TABLE <identifier> [<table_def>]
create_table::{
name: identifier,
definition: optional::table_definition,
// This is an expression for backward compatibility
// For now, we support `PARTITION BY (<id> (, <id>)* ))`
// But in the future, we might support additional partition expressions:
// such as `PARTITION BY RANGE(..)`
partition_by: optional::partition_by,
table_properties: list::[table_property],
},

// CREATE INDEX [<identifier>] ON <identifier> (<path> [, <path>]...)
create_index::{
index: optional::identifier,
table: identifier,
fields: list::[path],
},

// DROP TABLE <identifier>
drop_table::{
table: identifier,
},

// DROP INDEX <identifier> ON <identifier>
drop_index::{
index: identifier, // <identifier>[0]
table: identifier, // <identifier>[1]
},
]

// PartiQL Type AST nodes
//
// Several of these are the same "type", but have various syntax rules we wish to capture.
Expand Down Expand Up @@ -202,48 +193,10 @@ type::[
timestamp_with_tz::{ precision: optional::int }, // TIMESTAMP [(<int>)] WITH TIMEZONE
interval::{ precision: optional::int }, // INTERVAL
bag::{}, // BAG
// Potential migration strategy:
// v0.14.x -- the current state in `main`
// typeList()
//
// v0.15.x -- the next release
// @Deprecated // recommend using `typeArray()`
// typeList()
// typeArray(...)
//
// v1.0.x
// typeArray(...) // `typeList` now deleted
list::{}, // LIST
array::{ type: optional::type }, // ARRAY [<type>]
sexp::{}, // SEXP
// Potential migration strategy:
// v0.14.x -- the current state in `main`
// typeTuple()
// typeStruct()
//
// v0.15.x -- the next release
// @Deprecated // recommend using `typeStruct`
// typeTuple()
// typeStruct(fields = ...)
//
// v1.0.x
// typeStruct(fields = ...) // `typeTuple` now deleted
tuple::{}, // TUPLE
struct::{
fields: list::[field],
_ : [
field :: {
name: '.identifier.symbol',
type: '.type',
// This could be a boolean flag since we only support NOT NULL constraint
// for struct subfield. But modeling this to be a list of constraints
// to prevent future breaking changes.
constraints: list::[constraint],
is_optional: bool,
comment: optional::string,
}
],
}, // STRUCT <fields>
struct::{}, // STRUCT
any::{}, // ANY
custom::{ name: string }, // <symbol>
]
Expand Down Expand Up @@ -829,48 +782,31 @@ returning::{
],
}

// `<column_name> <type> <column_constraint>*`
// `( CONSTRAINT <column_constraint_name> )? <column_constraint_def>`
table_definition::{
attributes: list::[attribute],
// table level constraints
constraints: list::[constraint],
columns: list::[column],
_: [
attribute::{
name: '.identifier.symbol',
column::{
name: string,
type: '.type',
constraints: list::[constraint],
// TODO: Consider to model this as a constraint?
is_optional: bool,
comment: optional::string,
}
],
}

constraint::{
name: optional::string,
definition: [
nullable::{},
not_null::{},
check::{ expr: expr },
unique::{
// for attribute level constraint, we can set this attribute to null
attributes: optional::list::['.identifier.symbol'],
is_primary_key: bool,
_: [
// TODO improve modeling language to avoid these wrapped unions
// Also, prefer not to nest more than twice
constraint::{
name: optional::string,
body: [
nullable::{},
not_null::{},
check::{ expr: expr },
],
},
],
},
],
}

partition_by::[
attr_list :: {
list: list::['.identifier.symbol']
},
// We can add other commonly support Partition Expression like `range` later
]

table_property::{
name: string,
value: '.value',
}

// SQL-99 Table 11
datetime_field::[
YEAR, // 0001-9999
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,31 +407,15 @@ class ToLegacyAstTest {
expect("(struct_type)") { typeStruct() },
expect("(tuple_type)") { typeTuple() },
expect("(list_type)") { typeList() },
expect("(list_type)") { typeArray(null) },
expect("(sexp_type)") { typeSexp() },
expect("(bag_type)") { typeBag() },
expect("(any_type)") { typeAny() },
// Other (??)
expect("(integer4_type)") { typeInt4() },
expect("(integer8_type)") { typeInt8() },
expect("(custom_type dog)") { typeCustom("dog") },
expect("(custom_type dog)") { typeCustom("dog") }
// LEGACY AST does not have TIMESTAMP or INTERVAL
// LEGACY AST does not have parameterized blob/clob
// LEGACY AST does not support struct with field declaration
fail("The legacy AST does not support field declaration in struct type") {
typeStruct {
fields += org.partiql.ast.typeStructField(
org.partiql.ast.identifierSymbol("a", Identifier.CaseSensitivity.INSENSITIVE),
typeInt2(),
emptyList(),
false,
null
)
}
},
fail("The legacy AST does not support element type declaration for list") {
typeArray(typeInt2())
},
)

@JvmStatic
Expand Down
Loading
Loading