partiql-lang-kotlin icon indicating copy to clipboard operation
partiql-lang-kotlin copied to clipboard

Unused Returning Clause in Parser

Open johnedquinn opened this issue 2 years ago • 0 comments

Description

While working on replacing the SqlParser with our new PartiQLParser on branch ANTLR, I came across a weird scenario in the existing parser.

Essentially, as part of DML, the UPDATE keyword allows you to wrap any base DML (such as INSERT) with a RETURNING clause. Oddly, however, INSERT also allows for a RETURNING clause -- which made me think of what it would result in if we were to use both in a single query.

See Example #001 below:

PartiQL> UPDATE a INSERT INTO B VALUE C RETURNING MODIFIED NEW D RETURNING MODIFIED NEW E
   | !!

and here's the result:

(
  dml
  (
    operations
    (
      dml_op_list
      (
        insert_value
        (
          id
          B
          (
            case_insensitive
          )
          (
            unqualified
          )
        )
        (
          id
          C
          (
            case_insensitive
          )
          (
            unqualified
          )
        )
        null
        null
      )
    )
  )
  (
    from
    (
      scan
      (
        id
        a
        (
          case_insensitive
        )
        (
          unqualified
        )
      )
      null
      null
      null
    )
  )
  (
    returning
    (
      returning_expr
      (
        returning_elem
        (
          modified_new
        )
        (
          returning_column
          (
            id
            E
            (
              case_insensitive
            )
            (
              unqualified
            )
          )
        )
      )
    )
  )
)

As you can see, no reference to RETURNING ... D.

What's also interesting is that we also mess up collecting the remaining children. See Example #002:

PartiQL> UPDATE a INSERT INTO B VALUE C RETURNING MODIFIED NEW E INSERT INTO F VALUE G
   | !!

This results in the following exception:

org.partiql.lang.syntax.ParserException: Unprocessed components remaining
	Parser Error: at line <UNKNOWN>, column <UNKNOWN>: Internal error - malformed parse tree detected, <UNKNOWN> : <UNKNOWN>

	at org.partiql.lang.syntax.SqlParser$ParseNode.errMalformedParseTree(SqlParser.kt:256)
	at org.partiql.lang.syntax.SqlParser.malformedIfNotEmpty(SqlParser.kt:272)
	at org.partiql.lang.syntax.SqlParser.toDmlOperation(SqlParser.kt:1361)
	at org.partiql.lang.syntax.SqlParser.access$toDmlOperation(SqlParser.kt:79)
	at org.partiql.lang.syntax.SqlParser$toAstDml$1.invoke(SqlParser.kt:733)
        ....

Running this through the debugger, withing toDmlOperation, our unconsumed children includes the RETURNING node.

Recommendation

So, there are a couple things wrong. My recommendation (for the ANTLR project) would be to only allow RETURNING after the baseDml -- not within Dml (INSERT INTO .. VALUE) itself. This helps with ambiguity, and our AST only allows a single returning anyways (unless multiple column references).

This will likely be resolved with ANTLR's implementation, but it's something to keep in mind.

johnedquinn avatar Aug 04 '22 07:08 johnedquinn