Skip to content
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
12 changes: 7 additions & 5 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -4791,11 +4791,13 @@ TOKEN:
(
// Backslash escapes and doubled quotes; trimmed below to the rules in effect
("'" ( "\\" ~[] | "''" | ~["'", "\\"] )* "'") | ("'" ("''" | ~["'"])* "'")
// Alternative Oracle Escape Modes
| ("q'{" (~[])* "}'")
| ("q'(" (~[])* ")'")
| ("q'[" (~[])* "]'")
| ("q''" (~[])* "''")
// Alternative Oracle Escape Modes, up to the first closing delimiter
// followed by a quote: a body cannot contain that pair, so the longest
// match stops there and cannot run on to a later literal
| ("q'{" ( ~["}"] | ("}")+ ~["}", "'"] )* ("}")+ "'")
| ("q'(" ( ~[")"] | (")")+ ~[")", "'"] )* (")")+ "'")
| ("q'[" ( ~["]"] | ("]")+ ~["]", "'"] )* ("]")+ "'")
| ("q''" ( ~["'"] | "'" ~["'"] )* "''")
// | ("q'\\" (~[])* "\\'") <--- Does not work
)
// PostgreSQL Unicode escape string with an optional UESCAPE clause, see
Expand Down
52 changes: 52 additions & 0 deletions src/test/java/net/sf/jsqlparser/expression/StringValueTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashSet;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
Expand All @@ -24,9 +27,13 @@
import net.sf.jsqlparser.statement.create.table.ColumnOption;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.test.TestUtils;
import net.sf.jsqlparser.util.TablesNamesFinder;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

/**
*
Expand Down Expand Up @@ -369,6 +376,51 @@ public void testOracleAlternativeQuoting() throws JSQLParserException {
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@ParameterizedTest
@ValueSource(strings = {"q'{a}'", "q'(a)'", "q'[a]'", "q''a''", "Q'[a]'"})
void testOracleAlternativeQuotingEndsAtFirstDelimiter(String literal)
throws JSQLParserException {
String sqlStr =
"SELECT " + literal + " FROM t WHERE id IN (SELECT id FROM secrets) AND x = "
+ literal;

Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);

assertEquals(new HashSet<>(Arrays.asList("t", "secrets")),
new TablesNamesFinder<Void>().getTables(statement));
assertEquals(3, CCJSqlParserUtil.parseStatements(
"SELECT " + literal + " FROM t; DELETE FROM u; SELECT " + literal + " FROM t")
.size());
}

@Test
void testOracleAlternativeQuotingKeepsOneLiteralPerQuote() throws JSQLParserException {
PlainSelect select = (PlainSelect) TestUtils
.assertSqlCanBeParsedAndDeparsed("SELECT q'[a]' || q'[b]' FROM dual", true);

Concat concat = (Concat) select.getSelectItem(0).getExpression();
assertEquals("[a]", ((StringValue) concat.getLeftExpression()).getValue());
assertEquals("[b]", ((StringValue) concat.getRightExpression()).getValue());
}

@ParameterizedTest
@CsvSource(delimiter = '|', quoteCharacter = '"', value = {
"q'[a]b]'|[a]b]",
"q'[a]]'|[a]]",
"q'[]'|[]",
"q'[]]'|[]]",
"q'[it's]'|[it's]",
"q'(a)b)'|(a)b)",
"q'{a}}'|{a}}",
"q''a'b''|'a'b'"})
void testOracleAlternativeQuotingBody(String literal, String value)
throws JSQLParserException {
PlainSelect select = (PlainSelect) TestUtils
.assertSqlCanBeParsedAndDeparsed("SELECT " + literal + " FROM dual", true);

assertEquals(value, ((StringValue) select.getSelectItem(0).getExpression()).getValue());
}

@Test
public void testParseInput_BYTEA() throws Exception {
String sqlStr = "VALUES (X'', X'01FF', X'01 bc 2a', X'01' '02')";
Expand Down