Skip to content

v0.2 to v0.3 upgrade

yliuuuu edited this page Nov 2, 2022 · 4 revisions

v0.3.* (latest v0.3.4)

New features

  • DATE and TIME data types
  • Parser support for
    • Multiple SET, REMOVE operations per DML statement
    • ON CONFLICT and RETURNING DML clause
    • ORDER BY clause (not yet implemented in evaluator)
  • Redact function that removes potentially sensitive information from SQL queries, allowing them to be logged for later analysis
  • Optimizes AstNode’s Iterator

Deprecated items

Misc/bug fixes

  • [fix] parser handling of top-level tokens
  • [fix] SIZE ExprFunction to work with s-expressions
  • [fix] Change usage of LazyThreadSafetyMode from NONE to PUBLICATION

Breaking changes

Breaking API changes

NOTE: ExprNode is deprecated and replaced with PartiqlAst. Users can look at ExprNodeToStatement.kt and RewriterToVisitorTransformGuide.md to see how to update from ExprNode to PartiqlAst.

  1. Replace SourcePosition in Token with SourceSpan
// ----- v0.2.* -----
val ion = IonSystemBuilder.standard().build()
// `SqlLexer` provides us with `Token`s
val tokens = SqlLexer(ion).tokenize("42")
val firstToken = tokens.first()

// `Token`s defined in v0.2.* and before used `SourcePosition` specifying the `line` and `column` of a `Token`
val tokenFromConstructor = Token(
    type = TokenType.LITERAL,
    value = ion.singleValue("42"),
    position = SourcePosition(
        line = 1,
        column = 1
    )
)
assertEquals(tokenFromConstructor, firstToken)
// ----- v0.3.* -----
// `Token`s defined in v0.3.* onwards used `SourceSpan` specifying the `line`, `column`, and length of a `Token`
val tokenFromConstructor = Token(
    type = TokenType.LITERAL,
    value = ion.singleValue("42"),
    span = SourceSpan(
        line = 1,
        column = 1,
        length = 2
    )
)
assertEquals(tokenFromConstructor, firstToken)
  1. Removed PARSE_EXEC_AT_UNEXPECTED_LOCATION error code from ErrorCode
// ----- v0.2.* -----
val ion = IonSystemBuilder.standard().build()
val parser = SqlParser(ion)

// bad query containing a stored procedure call, `EXEC`, at an unexpected location
val badQuery = "SELECT * FROM (EXEC undrop 'foo')"

try {
    parser.parseExprNode(badQuery)
} catch (pe: ParserException) {
    // the parser gives a `ParserException` with error code `PARSE_EXEC_AT_UNEXPECTED_LOCATION`, which is
    // removed starting in v0.3.* onwards
    assertEquals(ErrorCode.PARSE_EXEC_AT_UNEXPECTED_LOCATION, pe.errorCode)
}
// ----- v0.3.* -----
try {
    parser.parseExprNode(badQuery)
} catch (pe: ParserException) {
    // the parser gives a `ParserException` with error code `PARSE_UNEXPECTED_TERM` in v0.3.* onwards
    assertEquals(ErrorCode.PARSE_UNEXPECTED_TERM, pe.errorCode)
}
  1. Refactoring of ExprNode AST
  • AssignmentOp node stores one Assignment rather than a list
  • DataManipulation node stores a DmlOpList rather than a single DataManipulationOperation
// ----- v0.2.* -----
val ion = IonSystemBuilder.standard().build()
// In v0.2.* and before,
// - `DataManipulation` node can only specify a single `dmlOperation`
// - `AssignmentOp`, a type of `DataManipulationOperation` contains a list of `Assignments`
// The following AST represents the DML query (without source location metas): SET k = 5, l = 6
DataManipulation(
    dmlOperation = AssignmentOp(
        assignments = listOf(
            Assignment(
                lvalue = VariableReference(
                    id = "k",
                    case = CaseSensitivity.INSENSITIVE,
                    metas = emptyMetaContainer
                ),
                rvalue = Literal(
                    ionValue = ion.singleValue("5"),
                    metas = emptyMetaContainer
                )
            ),
            Assignment(
                lvalue = VariableReference(
                    id = "l",
                    case = CaseSensitivity.INSENSITIVE,
                    metas = emptyMetaContainer
                ),
                rvalue = Literal(
                    ionValue = ion.singleValue("6"),
                    metas = emptyMetaContainer
                )
            )
        )
    ),
    metas = emptyMetaContainer
)
// ----- v0.3.* -----
// In v0.3.* onwards,
// - `DataManipulation` node specifies a list of `dmlOperation`s
// - `AssignmentOp`, a type of `DataManipulationOperation` contains a single assignment
// The following AST represents the DML query (without source location metas): SET k = 5, l = 6
DataManipulation(
    dmlOperations = DmlOpList(
        ops = listOf(
            AssignmentOp(
                assignment = Assignment(
                    lvalue = VariableReference(
                        id = "k",
                        case = CaseSensitivity.INSENSITIVE,
                        metas = emptyMetaContainer
                    ),
                    rvalue = Literal(
                        ionValue = ion.singleValue("5"),
                        metas = emptyMetaContainer
                    )
                )
            ),
            AssignmentOp(
                assignment = Assignment(
                    lvalue = VariableReference(
                        id = "l",
                        case = CaseSensitivity.INSENSITIVE,
                        metas = emptyMetaContainer
                    ),
                    rvalue = Literal(
                        ionValue = ion.singleValue("6"),
                        metas = emptyMetaContainer
                    )
                )
            )
        )
    ),
    metas = emptyMetaContainer
)
Clone this wiki locally