Skip to content

Commit

Permalink
RD-10961+RD-10948 (#435)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Zerntev <alexzerntev@gmail.com>
  • Loading branch information
bgaidioz and Alexzerntev committed May 30, 2024
1 parent ff0cf7b commit 8d54269
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -699,10 +699,10 @@ class RawSqlVisitor(

override def visitIdnt(ctx: PsqlParser.IdntContext): SqlBaseNode = Option(ctx)
.map { context =>
val isDoubleQuoted = context.DOUBLE_QUOTED_STRING() != null
val isDoubleQuoted = context.STRING_IDENTIFIER_START() != null
val value =
if (isDoubleQuoted) {
val text = context.DOUBLE_QUOTED_STRING().getText
val text = context.getText
val withoutLast =
if (!text.endsWith("\"")) {
addError("Missing closing \"", context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -963,4 +963,39 @@ class TestSqlCompilerServiceAirports
assert(v.messages.exists(_.message contains "the input does not form a valid statement or expression"))
}

test("""RD-10948+10961""") { _ =>
assume(password != "")
val q = """:
|""".stripMargin
val ValidateResponse(errors) = compilerService.validate(q, asJson())
assert(errors.nonEmpty)
}

test("""RD-10948""") { _ =>
assume(password != "")
val q = """SELECT * FROM
|(VALUES
| (1, 'janedoe', 'janedoe@raw-labs.com', '123'),
| (2, 'janedoe', 'janedoe@raw-labs.com', '123')
|) as i(id, first_name, email, password)
|WHERE email = :email AND password:
|""".stripMargin
val ValidateResponse(errors) = compilerService.validate(q, asJson())
assert(errors.nonEmpty)
}

test("""RD-10961""") { _ =>
assume(password != "")
val q = """-- @default id 1
|
|SELECT * FROM
|(VALUES
| (1, 'John', 'Doe', DATE '2023-01-02'),
| (2, 'Jane', 'Doe', DATE '2024-01-03')
|) as i(id, first_name, last_name, birthday)
|WHERE id = :id && id = :
|""".stripMargin
val ValidateResponse(errors) = compilerService.validate(q, asJson())
assert(errors.nonEmpty)
}
}
89 changes: 51 additions & 38 deletions sql-client/src/test/scala/raw/client/sql/TestSqlParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import raw.client.sql.antlr4.{
SqlProgramNode,
SqlProjNode,
SqlStatementNode,
SqlStringLiteralNode,
SqlWithComaSeparatorNode
}

Expand Down Expand Up @@ -242,7 +243,7 @@ class TestSqlParser extends AnyFunSuite {
}

test("Test multiple param occurrences") {
val code = """SELECT * FROM example.airports WHERE city = :param and airport_id = :param"""".stripMargin
val code = """SELECT * FROM example.airports WHERE city = :param and airport_id = :param""".stripMargin
val result = doTest(code)
assert(result.isSuccess)
result.params.get("param") match {
Expand Down Expand Up @@ -409,28 +410,6 @@ class TestSqlParser extends AnyFunSuite {
assert(result.isSuccess)
}

test("Test missing closing double quote identifier") {
val code = """select somethin."asdf from anything""".stripMargin
val result = doTest(code)
assert(result.errors.size == 1)
assert(
result.errors.head.message == "Missing closing \""
)
result.tree match {
case SqlProgramNode(statement) => statement match {
case SqlStatementNode(statementItems) =>
assert(statementItems.size == 4)
statementItems(1) match {
case SqlProjNode(identifiers) => identifiers(1) match {
case identifier: SqlIdentifierNode =>
assert(identifier.name == "asdf")
assert(identifier.isQuoted)
}
}
}
}
}

test("Test missing identifier after dot") {
val code = """SELECT * FROM example.airports
|WHERE ai.
Expand Down Expand Up @@ -582,33 +561,67 @@ class TestSqlParser extends AnyFunSuite {
assert(result.isSuccess)
}

ignore("double quoted identifier with a newline, in the end of the code") {
val code = """SELECT * FROM x
|WHERE example."c si
|
|
|bon"
test("single quoted string with a newline") {
val code = """SELECT 'c
| si
| bon' FROM x
|""".stripMargin
val result = doTest(code)
assert(result.isSuccess)
}

ignore("-- double quoted identifier with a newline, in the end of the code") {
val code = """SELECT * FROM x
|WHERE example."c
|si
|bon
test("single quoted identifier with a newline") {
val code = """SELECT "c
| si
| bon" FROM x
|""".stripMargin
val result = doTest(code)
assert(result.isSuccess)
}

ignore("single quoted string with a newline, in the end of the code") {
val code = """SELECT 'c
| si
| bon' FROM x
test("colon in the end of the code with a newline") {
val code = """:
|""".stripMargin
val result = doTest(code)
assert(result.isSuccess)
val SqlProgramNode(stmt) = result.tree
assert(result.positions.getStart(stmt).isDefined)
assert(result.positions.getStart(stmt).flatMap(_.optOffset).isDefined)
assert(result.positions.getFinish(stmt).flatMap(_.optOffset).isDefined)
}

test("multiline string-identifier test") {
val code = """select "
|a
|" from anything """.stripMargin
val result = doTest(code)
val SqlProgramNode(stmt) = result.tree
stmt match {
case SqlStatementNode(statementItems) =>
assert(statementItems.size == 4)
statementItems(1) match {
case node: SqlIdentifierNode =>
val finish = result.positions.getFinish(node)
assert(finish.get.line == 3)
}
}
}

test("multiline string test") {
val code = """select '
|a
|' from anything """.stripMargin
val result = doTest(code)
val SqlProgramNode(stmt) = result.tree
stmt match {
case SqlStatementNode(statementItems) =>
assert(statementItems.size == 4)
statementItems(1) match {
case node: SqlStringLiteralNode =>
val finish = result.positions.getFinish(node)
assert(finish.get.line == 3)
}
}
}

}
21 changes: 15 additions & 6 deletions sql-parser/src/main/java/raw/psql/grammar/PsqlLexer.g4
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
lexer grammar PsqlLexer;

UNICODE: 'U&';

// Comments
LINE_COMMENT_START: '--' -> pushMode(INSIDE_SINGLE_LINE_COMMENT);

MULTI_LINE_COMMENT_START: '/*' -> pushMode(INSIDE_MULTI_LINE_COMMENT);

QUOTE: '\'';
STRING_LITERAL_START: '\'' -> pushMode(INSIDE_STRING_LITERAL);
STRING_IDENTIFIER_START: '"' -> pushMode(INSIDE_STRING_IDENTIFIER);

DOT: '.';
STAR: '*';
COMMA: ',';
Expand Down Expand Up @@ -44,8 +48,6 @@ CONCAT: '||';
REGEX_CASE_INSENSITIVE_MATCH: '~*';
REGEX_CASE_INSENSITIVE_NOT_MATCH: '!~*';

UNICODE: 'U&';


DOUBLE_COLON: '::';

Expand All @@ -55,8 +57,6 @@ FLOATING_POINT: DIGIT+ '.' DIGIT* EXPONENT?;
PARAM: ':' WORD;

// Strings
DOUBLE_QUOTED_STRING: '"' (~[" \u0000] | '""')* '"'?;
SINGLE_QUOTED_STRING: '\'' (ESC | ~['\\])* '\'';
TICKS_QUOTED_STRING: '`' (ESC | ~[`\\])* '`';

BIGSERIAL: B I G S E R I A L;
Expand Down Expand Up @@ -1009,7 +1009,16 @@ ML_STAR: '*';
mode INSIDE_UNKNOWN_WORD;
UNKNOWN_WORD_END: [ \t\r\n;EOF] -> popMode;
UNKNOWN_WORD_END: [ \t\r\n;EOF] -> popMode, skip;
UNKNOWN_WORD_END2: [)] -> type(R_PAREN), popMode;
IN_UNKNOWN_WORD: ~[;)];
mode INSIDE_STRING_LITERAL;
STRING_LITERAL_END: '\'' -> popMode;
STRING_LITERAL_CONTENT: (ESC | ~['\\]);
mode INSIDE_STRING_IDENTIFIER;
STRING_ESCAPE: '"' '"';
STRING_IDENTIFIER_END: '"' -> popMode;
STRING_IDENTIFIER_CONTENT: (ESC | ~["]);
Loading

0 comments on commit 8d54269

Please sign in to comment.