test: cover mergeWithNoWhenClauseFailsToParse
This commit is contained in:
1 parent
742eeef126
commit
40197f5dc9
1 file changed
+173
@@ -938,4 +938,177 @@ class ParserTest {
|
||||
) as MergeStatement
|
||||
assertEquals(3, statement.whenClauses.size)
|
||||
assertTrue(statement.whenClauses[0] is MergeMatchedDelete)
|
||||
assertTrue(statement.whenClauses[1] is MergeMatchedUpdate)
|
||||
assertTrue(statement.whenClauses[2] is MergeNotMatchedInsert)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeWithNoWhenClauseFailsToParse() {
|
||||
assertFailsWith<ParseException> { parseOne("MERGE INTO t USING s ON t.id = s.id") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeWhenMatchedRequiresUpdateOrDelete() {
|
||||
assertFailsWith<ParseException> { parseOne("MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN INSERT (id) VALUES (s.id)") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeWhenNotMatchedOnlySupportsInsert() {
|
||||
assertFailsWith<ParseException> { parseOne("MERGE INTO t USING s ON t.id = s.id WHEN NOT MATCHED THEN DELETE") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeWithoutReturningLeavesItNull() {
|
||||
val statement = parseOne("MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN DELETE") as MergeStatement
|
||||
assertNull(statement.returning)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeReturningStarParsesAsStarProjectionAfterTheLastWhenClause() {
|
||||
val statement = parseOne(
|
||||
"MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN DELETE RETURNING *"
|
||||
) as MergeStatement
|
||||
assertEquals(StarProjection, statement.returning)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeReturningExpressionListParsesLikeASelectProjection() {
|
||||
val statement = parseOne(
|
||||
"MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN DELETE RETURNING id, MERGE_ACTION() AS kind"
|
||||
) as MergeStatement
|
||||
val projection = statement.returning as ExpressionProjection
|
||||
assertEquals(2, projection.items.size)
|
||||
assertEquals("id", (projection.items[0].expression as ColumnExpression).name)
|
||||
assertNull(projection.items[0].alias)
|
||||
assertEquals(MergeActionExpression, projection.items[1].expression)
|
||||
assertEquals("kind", projection.items[1].alias)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeActionParsesAsItsOwnExpressionNode() {
|
||||
val select = parseOne("SELECT MERGE_ACTION() FROM t") as SelectStatement
|
||||
val items = (select.projection as ExpressionProjection).items
|
||||
assertEquals(MergeActionExpression, items.single().expression)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mergeActionTakesNoArguments() {
|
||||
assertFailsWith<ParseException> { parse("SELECT MERGE_ACTION(1)") }
|
||||
assertFailsWith<ParseException> { parse("SELECT MERGE_ACTION('x')") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parsesDecimalColumnWithAndWithoutPrecisionAndScale() {
|
||||
val statement = parseOne(
|
||||
"CREATE TABLE t (bare DECIMAL, scaled DECIMAL(10), precise DECIMAL(10, 2))"
|
||||
) as CreateTableStatement
|
||||
assertEquals(ColumnType.Decimal, statement.columns[0].type)
|
||||
assertNull(statement.columns[0].precision)
|
||||
assertNull(statement.columns[0].scale)
|
||||
assertEquals(10, statement.columns[1].precision)
|
||||
assertEquals(0, statement.columns[1].scale)
|
||||
assertEquals(10, statement.columns[2].precision)
|
||||
assertEquals(2, statement.columns[2].scale)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parsesDateColumn() {
|
||||
val statement = parseOne("CREATE TABLE t (born DATE)") as CreateTableStatement
|
||||
assertEquals(ColumnType.Date, statement.columns[0].type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parsesCastExpressionWithAndWithoutPrecisionAndScale() {
|
||||
val plain = firstProjection("SELECT CAST(a AS INTEGER) FROM t") as CastExpression
|
||||
assertEquals(ColumnType.Integer, plain.targetType)
|
||||
assertNull(plain.precision)
|
||||
|
||||
val decimal = firstProjection("SELECT CAST(a AS DECIMAL(10, 2)) FROM t") as CastExpression
|
||||
assertEquals(ColumnType.Decimal, decimal.targetType)
|
||||
assertEquals(10, decimal.precision)
|
||||
assertEquals(2, decimal.scale)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parsesCollateExpressionWithEachBuiltInSequenceCaseInsensitively() {
|
||||
val nocase = firstProjection("SELECT name COLLATE NOCASE FROM t") as CollateExpression
|
||||
assertEquals(Collation.NoCase, nocase.collation)
|
||||
assertEquals(ColumnExpression("name"), nocase.operand)
|
||||
|
||||
val rtrim = firstProjection("SELECT name COLLATE rtrim FROM t") as CollateExpression
|
||||
assertEquals(Collation.Rtrim, rtrim.collation)
|
||||
|
||||
val binary = firstProjection("SELECT name COLLATE BINARY FROM t") as CollateExpression
|
||||
assertEquals(Collation.Binary, binary.collation)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collateWithAnUnknownSequenceNameFailsToParse() {
|
||||
assertFailsWith<ParseException> { parse("SELECT name COLLATE BOGUS FROM t") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collateWithoutAFollowingNameFailsToParse() {
|
||||
assertFailsWith<ParseException> { parse("SELECT name COLLATE FROM t") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collateBindsTighterThanComparisonSoItWrapsOnlyTheColumnItFollows() {
|
||||
val where = whereOf("SELECT 1 FROM t WHERE name COLLATE NOCASE = 'bob'")
|
||||
val comparison = where as BinaryExpression
|
||||
assertEquals(BinaryOperator.Equal, comparison.operator)
|
||||
val left = comparison.left as CollateExpression
|
||||
assertEquals(Collation.NoCase, left.collation)
|
||||
assertEquals(ColumnExpression("name"), left.operand)
|
||||
assertEquals(LiteralExpression(Value.TextValue("bob")), comparison.right)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collateBindsTighterThanMultiplicationSoItWrapsOnlyItsOwnOperand() {
|
||||
val projection = firstProjection("SELECT a * b COLLATE NOCASE FROM t") as BinaryExpression
|
||||
assertEquals(BinaryOperator.Multiply, projection.operator)
|
||||
assertEquals(ColumnExpression("a"), projection.left)
|
||||
val right = projection.right as CollateExpression
|
||||
assertEquals(Collation.NoCase, right.collation)
|
||||
assertEquals(ColumnExpression("b"), right.operand)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collateBindsLooserThanUnaryMinusSoItWrapsTheWholeNegation() {
|
||||
val projection = firstProjection("SELECT -a COLLATE NOCASE FROM t") as CollateExpression
|
||||
assertEquals(Collation.NoCase, projection.collation)
|
||||
val negated = projection.operand as UnaryExpression
|
||||
assertEquals(UnaryOperator.Negate, negated.operator)
|
||||
assertEquals(ColumnExpression("a"), negated.operand)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chainedCollateWrapsEachPreviousCollateExpression() {
|
||||
val projection = firstProjection("SELECT a COLLATE BINARY COLLATE NOCASE FROM t") as CollateExpression
|
||||
assertEquals(Collation.NoCase, projection.collation)
|
||||
val inner = projection.operand as CollateExpression
|
||||
assertEquals(Collation.Binary, inner.collation)
|
||||
assertEquals(ColumnExpression("a"), inner.operand)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parsesColumnLevelCollateInCreateTable() {
|
||||
val statement = parseOne("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT COLLATE NOCASE, other TEXT)") as CreateTableStatement
|
||||
assertEquals(Collation.NoCase, statement.columns[1].collation)
|
||||
assertEquals(Collation.Binary, statement.columns[0].collation)
|
||||
assertEquals(Collation.Binary, statement.columns[2].collation)
|
||||
}
|
||||
|
||||
/**
|
||||
* COLLATE before DEFAULT is unambiguous: the column-definition loop consumes it as its own
|
||||
* clause before ever calling [Parser.parseExpression] for DEFAULT's value. The other order
|
||||
* (`DEFAULT 'x' COLLATE NOCASE`) is deliberately not covered here - `parseExpression` itself
|
||||
* accepts a trailing `COLLATE` (see `parseCollate`), so it greedily becomes part of the DEFAULT
|
||||
* expression instead (`DEFAULT ('x' COLLATE NOCASE)`), not a separate column-level clause; not a
|
||||
* bug, just the same expression-grammar greediness this column-level COLLATE reuses.
|
||||
*/
|
||||
@Test
|
||||
fun columnLevelCollateBeforeDefaultAttachesToTheColumnNotTheDefaultExpression() {
|
||||
val statement = parseOne("CREATE TABLE t (name TEXT COLLATE NOCASE DEFAULT 'x')") as CreateTableStatement
|
||||
assertEquals(Collation.NoCase, statement.columns[0].collation)
|
||||
}
|
||||
Reference in new issue
Block a user