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
31 changes: 28 additions & 3 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -2838,6 +2838,30 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
"SUBJECT").contains(token.image.toUpperCase(Locale.ROOT));
}

/** An unsupported CREATE statement that keeps OR REPLACE, which Create() has already read. */
private static UnsupportedStatement unsupportedCreate(boolean orReplace, List<String> rest) {
List<String> declarations = new ArrayList<String>();
if (orReplace) {
declarations.add("OR");
declarations.add("REPLACE");
}
declarations.addAll(rest);
return new UnsupportedStatement("CREATE", declarations);
}

/**
* Whether a CREATE statement names none of TABLE, INDEX, VIEW and POLICY before it ends. Every
* remaining CREATE form needs one of them, and CREATE TABLE and CREATE INDEX accept any leading
* words as modifiers, so such a statement would fail there instead of reaching the fallback.
*/
private boolean isUnknownCreateAhead() {
for (int i = 1; ; i++) {
int kind = getToken(i).kind;
if (kind == EOF || kind == ST_SEMICOLON) { return true; }
if (kind == K_TABLE || kind == K_INDEX || kind == K_VIEW || kind == K_POLICY) { return false; }
}
}

/**
* Whether ALTER USER uses MySQL account syntax rather than the PostgreSQL alias of ALTER ROLE,
* which names one unquoted role followed by an action: IF EXISTS, USER(), a quoted name, a
Expand Down Expand Up @@ -23579,6 +23603,9 @@ Statement Create():
|
statement = CreateSynonym(isUsingOrReplace)
|
LOOKAHEAD({ isUnknownCreateAhead() }) captureRest = captureRest()
{ statement = unsupportedCreate(isUsingOrReplace, captureRest); }
|
LOOKAHEAD(3) statement = CreateTable(isUsingOrReplace)
|
LOOKAHEAD(2) statement = CreateView(isUsingOrReplace)
Expand All @@ -23592,9 +23619,7 @@ Statement Create():
statement = CreateIndex()
|
captureRest = captureRest()
{
statement = new UnsupportedStatement("CREATE", captureRest);
}
{ statement = unsupportedCreate(isUsingOrReplace, captureRest); }
)
{
return statement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,24 @@
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Arrays;
import java.util.function.Consumer;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
import net.sf.jsqlparser.parser.CCJSqlParser;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.alter.AlterRelation;
import net.sf.jsqlparser.statement.create.index.CreateIndex;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.trigger.CreateTrigger;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.test.TestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class UnsupportedStatementTest {
@Test
Expand Down Expand Up @@ -196,6 +204,39 @@ void testInformixSetStatementIssue1945() throws JSQLParserException {
"set isolation to dirty read;", true, parser -> parser.withUnsupportedStatements());
}

@ParameterizedTest
@ValueSource(strings = {
"CREATE LANGUAGE plperl",
"CREATE OR REPLACE TRUSTED PROCEDURAL LANGUAGE plsample HANDLER plsample_call_handler",
"CREATE OPERATOR CLASS gist__int_ops DEFAULT FOR TYPE _int4 USING gist AS OPERATOR 3 &&",
"CREATE OPERATOR FAMILY myfam USING btree",
"CREATE DEFAULT CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM latin1_to_utf8",
"CREATE TRANSFORM FOR hstore LANGUAGE plpython3u (FROM SQL WITH FUNCTION "
+ "hstore_to_plpython(internal), TO SQL WITH FUNCTION plpython_to_hstore(internal))",
"CREATE OR REPLACE AGGREGATE myavg(float8) (SFUNC = float8_accum, STYPE = float8[])"})
void unknownCreateFallsBackToUnsupportedStatement(String sql) throws JSQLParserException {
for (Consumer<CCJSqlParser> dialect : Arrays.<Consumer<CCJSqlParser>>asList(parser -> {
}, parser -> parser.withDialect(Dialect.POSTGRESQL))) {
Statement statement = CCJSqlParserUtil.parse(sql, dialect);

assertInstanceOf(UnsupportedStatement.class, statement);
// the captured tokens render with single spaces; OR REPLACE is kept
assertEquals(sql.replaceAll("\\s+", ""), statement.toString().replaceAll("\\s+", ""));
}
}

@Test
void unknownCreateDoesNotStopAScript() throws JSQLParserException {
Statements statements = CCJSqlParserUtil.parseStatements(
"CREATE TABLE a (x int); CREATE LANGUAGE plperl; CREATE INDEX i ON a (x);",
parser -> parser.withDialect(Dialect.POSTGRESQL));

assertEquals(3, statements.size());
assertInstanceOf(CreateTable.class, statements.get(0));
assertInstanceOf(UnsupportedStatement.class, statements.get(1));
assertInstanceOf(CreateIndex.class, statements.get(2));
}

@Test
void testRedshiftSetStatementIssue1708() throws JSQLParserException {
Statement st = TestUtils.assertSqlCanBeParsedAndDeparsed(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.util.Arrays;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.UnsupportedStatement;
import net.sf.jsqlparser.statement.MySqlDefiner;
import net.sf.jsqlparser.statement.CreateFunctionalStatement;
import net.sf.jsqlparser.statement.Statements;
Expand Down Expand Up @@ -154,8 +154,9 @@ public void definerDispatchKeepsTriggersAndViews() throws JSQLParserException {
assertThat(CCJSqlParserUtil.parse("CREATE FUNCTION f() RETURNS int AS 'SELECT 1'"))
.isInstanceOf(CreateFunction.class)
.extracting(statement -> ((CreateFunction) statement).getDefiner()).isNull();
assertThatThrownBy(() -> CCJSqlParserUtil.parse("CREATE DEFINER = x EVENT e "
+ "ON SCHEDULE EVERY 1 DAY DO SELECT 1")).isInstanceOf(JSQLParserException.class);
// DEFINER is not modelled for EVENT, so the statement falls back like other unknown forms
assertThat(CCJSqlParserUtil.parse("CREATE DEFINER = x EVENT e "
+ "ON SCHEDULE EVERY 1 DAY DO SELECT 1")).isInstanceOf(UnsupportedStatement.class);
}

@Test
Expand Down
Loading