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
14 changes: 12 additions & 2 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -1879,6 +1879,13 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
// AS always starts an alias
if (kind == K_AS) return true;

// SAMPLE followed by a size or BLOCK starts a sampling clause.
if (kind == K_SAMPLE && (getToken(2).kind == OPENING_BRACKET
|| getToken(2).kind == K_BLOCK || getToken(2).kind == S_LONG
|| getToken(2).kind == S_DOUBLE)) {
return false;
}

// String-literal alias: SELECT col 'myAlias'
if (kind == S_CHAR_LITERAL) return true;

Expand Down Expand Up @@ -3038,6 +3045,7 @@ String NonReservedWord() :
| tk=<K_EXECUTE: "EXECUTE">
| tk=<K_EXPLAIN:"EXPLAIN">
| tk=<K_EXPLICIT:"EXPLICIT">
| tk=<K_EXTEND:"EXTEND">
| tk=<K_EXISTS:"EXISTS">
| tk=<K_EXTENDED:"EXTENDED">
| tk=<K_EXTRACT:"EXTRACT">
Expand Down Expand Up @@ -3231,6 +3239,7 @@ String NonReservedWord() :
| tk=<K_RTRIM: "RTRIM">
| tk=<K_SAFE_CAST: "SAFE_CAST">
| tk=<K_SAFE_CONVERT: "SAFE_CONVERT">
| tk=<K_SAMPLE:"SAMPLE">
| tk=<K_SAVEPOINT: "SAVEPOINT">
| tk=<K_SCHEDULE: "SCHEDULE">
| tk=<K_SCHEMA: "SCHEMA">
Expand Down Expand Up @@ -3366,7 +3375,8 @@ TOKEN: /* Reserved SQL Keywords and structural tokens */
| <K_ELSE:"ELSE">
| <K_EXCEPT: "EXCEPT">
| <K_EXCLUDES: "EXCLUDES"> /* Salesforce SOQL */
| <K_EXTEND:"EXTEND">
| <K_EXISTS:"EXISTS">
| <K_FBV:"FBV">
| <K_FETCH:"FETCH">
| <K_FINAL: "FINAL">
| <K_FALSE: "FALSE">
Expand Down Expand Up @@ -3420,7 +3430,7 @@ TOKEN: /* Reserved SQL Keywords and structural tokens */
| <K_QUALIFY: "QUALIFY">
| <K_RETURNING: "RETURNING">
| <K_RIGHT:"RIGHT">
| <K_SAMPLE: "SAMPLE">
| <K_SCRIPT: "SCRIPT">
| <K_SELECT: ("SELECT" | "SEL")>
| <K_SEMI : "SEMI">
| <K_SET:"SET">
Expand Down
65 changes: 62 additions & 3 deletions src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@

import java.util.stream.Stream;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.TernaryExpression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.statement.piped.FromQuery;
import net.sf.jsqlparser.statement.piped.SelectPipeOperator;
import net.sf.jsqlparser.expression.NotExpression;
import net.sf.jsqlparser.expression.MapExpression;
import net.sf.jsqlparser.expression.JdbcNamedParameter;
Expand All @@ -24,6 +28,7 @@
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SampleClause;
import net.sf.jsqlparser.statement.select.WithItem;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down Expand Up @@ -77,6 +82,26 @@ public void testGroupsAsIdentifier() throws JSQLParserException {
assertSqlCanBeParsedAndDeparsed("CREATE TABLE mytable (groups INT)", true);
}

// sample and extend are non-reserved in the common dialects and reach the
// parser as ordinary table and column names in downstream rewriting tools.
@Test
public void testSampleExtendAsIdentifier() throws JSQLParserException {
assertSqlCanBeParsedAndDeparsed("SELECT sample, extend FROM mytable", true);
assertSqlCanBeParsedAndDeparsed("SELECT mytable.extend FROM mytable", true);
assertSqlCanBeParsedAndDeparsed("SELECT * FROM mytable WHERE extend = 'x'", true);
assertSqlCanBeParsedAndDeparsed("UPDATE mytable SET sample = 1, extend = 'x' WHERE id = 1",
true);
assertSqlCanBeParsedAndDeparsed("INSERT INTO mytable (sample, extend) VALUES (1, 'x')",
true);
assertSqlCanBeParsedAndDeparsed("SELECT * FROM sample", true);
assertSqlCanBeParsedAndDeparsed("DELETE FROM sample WHERE extend = 'x'", true);
assertSqlCanBeParsedAndDeparsed("INSERT INTO sample (extend) VALUES ('x')", true);
assertSqlCanBeParsedAndDeparsed("SELECT a AS sample, b AS extend FROM mytable", true);
}

@ParameterizedTest
@ValueSource(strings = {"sample", "extend", "SaMpLe", "ExTeNd"})
void testSampleExtendImplicitAliases(String keyword) throws JSQLParserException {
// exists is a non-reserved keyword in the common dialects and reaches the
// parser as an ordinary column name in downstream rewriting tools.
@Test
Expand Down Expand Up @@ -116,7 +141,7 @@ void testExistsImplicitAliases(String keyword) throws JSQLParserException {
}

@ParameterizedTest
@ValueSource(strings = {"exists", "ExIsTs"})
@ValueSource(strings = {"exists", "ExIsTs", "sample", "extend", "SaMpLe", "ExTeNd"})
void testExistsCte(String keyword) throws JSQLParserException {
PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(
"WITH " + keyword + "(x) AS (SELECT 1) SELECT x FROM " + keyword, true);
Expand All @@ -130,7 +155,7 @@ void testExistsCte(String keyword) throws JSQLParserException {
}

@ParameterizedTest
@ValueSource(strings = {"exists", "ExIsTs"})
@ValueSource(strings = {"exists", "ExIsTs", "sample", "extend", "SaMpLe", "ExTeNd"})
void testExistsExpressionContexts(String keyword) throws JSQLParserException {
PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(
"SELECT ALL " + keyword + " FROM mytable");
Expand All @@ -142,7 +167,7 @@ void testExistsExpressionContexts(String keyword) throws JSQLParserException {
}

@ParameterizedTest
@ValueSource(strings = {"exists", "ExIsTs"})
@ValueSource(strings = {"exists", "ExIsTs", "sample", "extend", "SaMpLe", "ExTeNd"})
void testExistsTernaryOperand(String keyword) throws JSQLParserException {
PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(
"SELECT flag ? " + keyword + " : 0 FROM mytable", true);
Expand All @@ -152,6 +177,38 @@ void testExistsTernaryOperand(String keyword) throws JSQLParserException {
.getColumnName());
}

@ParameterizedTest
@ValueSource(strings = {"SAMPLE (10)", "SAMPLE BLOCK (10) SEED (1)",
"SAMPLE 0.1 OFFSET 1000", "USING SAMPLE 10 PERCENT (BERNOULLI)",
"TABLESAMPLE SYSTEM (10)"})
void testSampleClauseStaysClause(String clause) throws JSQLParserException {
PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(
"SELECT * FROM mytable " + clause, true);
Table table = assertInstanceOf(Table.class, select.getFromItem());
assertNull(table.getAlias());
SampleClause sample = table.getSampleClause();
assertNotNull(sample);
assertEquals(" " + clause, sample.toString());
}

@ParameterizedTest
@ValueSource(strings = {"sample", "extend", "SaMpLe", "ExTeNd"})
void testSampleExtendPipeExpression(String keyword) throws JSQLParserException {
FromQuery query = (FromQuery) assertSqlCanBeParsedAndDeparsed(
"FROM " + keyword + " |> EXTEND " + keyword + " AS x", true);
SelectPipeOperator operator = assertInstanceOf(SelectPipeOperator.class,
query.getPipeOperators().get(0));
assertEquals("EXTEND", operator.getOperatorName());
assertEquals(keyword, assertInstanceOf(Column.class,
operator.getSelectItems().get(0).getExpression()).getColumnName());
assertSqlCanBeParsedAndDeparsed(
"FROM mytable |> EXTEND " + keyword + "(x) AS x", true);
PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(
"SELECT ALL " + keyword + "(x) FROM mytable");
assertEquals(keyword, assertInstanceOf(Function.class,
select.getSelectItem(0).getExpression()).getName());
}

@Test
void testExistsColumnWithOracleJoin() throws JSQLParserException {
PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(
Expand Down Expand Up @@ -253,6 +310,8 @@ void testExistsBeforeNestedTernary() throws JSQLParserException {
assertEquals("exists", assertInstanceOf(Column.class, map.getEntries().get(0).getKey())
.getColumnName());
assertInstanceOf(TernaryExpression.class, map.getEntries().get(0).getValue());
}

// ERRORS introduces Exasol's IMPORT/EXPORT error clauses but is an ordinary name elsewhere,
// e.g. a DuckDB column holding the errors of an upstream step.
@Test
Expand Down
Loading