DBZ-252 add parser listeners for alter view and drop view statements + test for it
This commit is contained in:
parent
7d7f740721
commit
c3b65ac2c3
@ -37,7 +37,11 @@ public abstract class AntlrDdlParser<L extends Lexer, P extends Parser> extends
|
||||
protected DataTypeResolver dataTypeResolver = new DataTypeResolver();
|
||||
|
||||
public AntlrDdlParser(boolean throwErrorsFromTreeWalk) {
|
||||
super(";");
|
||||
this(throwErrorsFromTreeWalk, false);
|
||||
}
|
||||
|
||||
public AntlrDdlParser(boolean throwErrorsFromTreeWalk, boolean includeViews) {
|
||||
super(";", includeViews);
|
||||
this.throwErrorsFromTreeWalk = throwErrorsFromTreeWalk;
|
||||
}
|
||||
|
||||
@ -196,8 +200,8 @@ public void signalAlterTable(TableId id, TableId previousId, ParserRuleContext c
|
||||
}
|
||||
|
||||
@Override
|
||||
public void signalDropTable(TableId id, String ctx) {
|
||||
super.signalDropTable(id, ctx);
|
||||
public void signalDropTable(TableId id, String statement) {
|
||||
super.signalDropTable(id, statement);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,11 @@ public MySqlAntlrDdlParser() {
|
||||
}
|
||||
|
||||
public MySqlAntlrDdlParser(boolean throwErrorsFromTreeWalk) {
|
||||
super(throwErrorsFromTreeWalk);
|
||||
this(throwErrorsFromTreeWalk, false);
|
||||
}
|
||||
|
||||
public MySqlAntlrDdlParser(boolean throwErrorsFromTreeWalk, boolean includeViews) {
|
||||
super(throwErrorsFromTreeWalk, includeViews);
|
||||
systemVariables = new MySqlSystemVariables();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright Debezium Authors.
|
||||
*
|
||||
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
package io.debezium.antlr.mysql.listener;
|
||||
|
||||
import io.debezium.antlr.AntlrDdlParser;
|
||||
import io.debezium.antlr.mysql.MySqlAntlrDdlParser;
|
||||
import io.debezium.ddl.parser.mysql.generated.MySqlParser;
|
||||
import io.debezium.ddl.parser.mysql.generated.MySqlParserBaseListener;
|
||||
import io.debezium.relational.Column;
|
||||
import io.debezium.relational.TableEditor;
|
||||
import io.debezium.relational.TableId;
|
||||
import io.debezium.text.ParsingException;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Roman Kuchár <kucharrom@gmail.com>.
|
||||
*/
|
||||
public class AlterViewParserListener extends MySqlParserBaseListener {
|
||||
|
||||
private final MySqlAntlrDdlParser parserCtx;
|
||||
private final List<ParseTreeListener> listeners;
|
||||
|
||||
private TableEditor tableEditor;
|
||||
private ViewSelectedColumnsParserListener selectColumnsListener;
|
||||
|
||||
|
||||
public AlterViewParserListener(MySqlAntlrDdlParser parserCtx, List<ParseTreeListener> listeners) {
|
||||
this.parserCtx = parserCtx;
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterAlterView(MySqlParser.AlterViewContext ctx) {
|
||||
if (!parserCtx.skipViews()) {
|
||||
TableId tableId = parserCtx.parseQualifiedTableId(ctx.fullId());
|
||||
|
||||
tableEditor = parserCtx.databaseTables().editTable(tableId);
|
||||
if (tableEditor == null) {
|
||||
throw new ParsingException(null, "Trying to alter view " + parserCtx.getFullTableName(tableId)
|
||||
+ ", which does not exists. Query:" + AntlrDdlParser.getText(ctx));
|
||||
}
|
||||
// alter view will override existing columns for a new one
|
||||
tableEditor.columnNames().forEach(tableEditor::removeColumn);
|
||||
// create new columns just with specified name for now
|
||||
if (ctx.uidList() != null) {
|
||||
ctx.uidList().uid().stream().map(parserCtx::parseName).forEach(columnName -> {
|
||||
tableEditor.addColumn(Column.editor().name(columnName).create());
|
||||
});
|
||||
}
|
||||
selectColumnsListener = new ViewSelectedColumnsParserListener(tableEditor, parserCtx);
|
||||
listeners.add(selectColumnsListener);
|
||||
}
|
||||
super.enterAlterView(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitAlterView(MySqlParser.AlterViewContext ctx) {
|
||||
parserCtx.runIfNotNull(() -> {
|
||||
tableEditor.addColumns(selectColumnsListener.getSelectedColumns());
|
||||
// Make sure that the table's character set has been set ...
|
||||
if (!tableEditor.hasDefaultCharsetName()) {
|
||||
tableEditor.setDefaultCharsetName(parserCtx.currentDatabaseCharset());
|
||||
}
|
||||
parserCtx.databaseTables().overwriteTable(tableEditor.create());
|
||||
listeners.remove(selectColumnsListener);
|
||||
}, tableEditor);
|
||||
// signal view even if it was skipped
|
||||
parserCtx.signalAlterView(parserCtx.parseQualifiedTableId(ctx.fullId()), null, ctx);
|
||||
super.exitAlterView(ctx);
|
||||
}
|
||||
}
|
@ -37,8 +37,8 @@ public void enterCreateView(MySqlParser.CreateViewContext ctx) {
|
||||
tableEditor = parserCtx.databaseTables().editOrCreateTable(parserCtx.parseQualifiedTableId(ctx.fullId()));
|
||||
// create new columns just with specified name for now
|
||||
if (ctx.uidList() != null) {
|
||||
ctx.uidList().uid().forEach(uidContext -> {
|
||||
tableEditor.addColumn(Column.editor().name(parserCtx.parseName(uidContext)).create());
|
||||
ctx.uidList().uid().stream().map(parserCtx::parseName).forEach(columnName -> {
|
||||
tableEditor.addColumn(Column.editor().name(columnName).create());
|
||||
});
|
||||
}
|
||||
selectColumnsListener = new ViewSelectedColumnsParserListener(tableEditor, parserCtx);
|
||||
@ -58,7 +58,7 @@ public void exitCreateView(MySqlParser.CreateViewContext ctx) {
|
||||
parserCtx.databaseTables().overwriteTable(tableEditor.create());
|
||||
listeners.remove(selectColumnsListener);
|
||||
}, tableEditor);
|
||||
// TODO rkuchar move into lambda function
|
||||
// signal view even if it was skipped
|
||||
parserCtx.signalCreateView(parserCtx.parseQualifiedTableId(ctx.fullId()), ctx);
|
||||
super.exitCreateView(ctx);
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright Debezium Authors.
|
||||
*
|
||||
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
package io.debezium.antlr.mysql.listener;
|
||||
|
||||
import io.debezium.antlr.mysql.MySqlAntlrDdlParser;
|
||||
import io.debezium.ddl.parser.mysql.generated.MySqlParser;
|
||||
import io.debezium.ddl.parser.mysql.generated.MySqlParserBaseListener;
|
||||
|
||||
/**
|
||||
* @author Roman Kuchár <kucharrom@gmail.com>.
|
||||
*/
|
||||
public class DropViewParserListener extends MySqlParserBaseListener {
|
||||
|
||||
private final MySqlAntlrDdlParser parserCtx;
|
||||
|
||||
public DropViewParserListener(MySqlAntlrDdlParser parserCtx) {
|
||||
this.parserCtx = parserCtx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterDropView(MySqlParser.DropViewContext ctx) {
|
||||
ctx.fullId().stream().map(parserCtx::parseQualifiedTableId).forEach(tableId -> {
|
||||
parserCtx.databaseTables().removeTable(tableId);
|
||||
parserCtx.signalDropView(tableId, ctx);
|
||||
});
|
||||
super.enterDropView(ctx);
|
||||
}
|
||||
}
|
@ -49,6 +49,8 @@ public MySqlAntlrDdlParserListener(MySqlAntlrDdlParser parserCtx) {
|
||||
listeners.add(new RenameTableParserListener(parserCtx));
|
||||
listeners.add(new TruncateTableParserListener(parserCtx));
|
||||
listeners.add(new CreateViewParserListener(parserCtx, listeners));
|
||||
listeners.add(new AlterViewParserListener(parserCtx, listeners));
|
||||
listeners.add(new DropViewParserListener(parserCtx));
|
||||
listeners.add(new CreateUniqueIndexParserListener(parserCtx));
|
||||
listeners.add(new SetStatementParserListener(parserCtx));
|
||||
listeners.add(new UseStatementParserListener(parserCtx));
|
||||
|
@ -107,6 +107,102 @@ public void shouldParseCreateTableStatementWithSingleGeneratedAndPrimaryKeyColum
|
||||
assertColumn(foo, "c2", "VARCHAR", Types.VARCHAR, 22, -1, true, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseCreateViewStatementStartSelect() {
|
||||
String ddl = "CREATE TABLE foo ( " + System.lineSeparator()
|
||||
+ " c1 INTEGER NOT NULL AUTO_INCREMENT, " + System.lineSeparator()
|
||||
+ " c2 VARCHAR(22) " + System.lineSeparator()
|
||||
+ "); " + System.lineSeparator();
|
||||
String ddl2 = "CREATE VIEW fooView AS (SELECT * FROM foo)" + System.lineSeparator();
|
||||
|
||||
parser = new MysqlDdlParserWithSimpleTestListener(listener, true);
|
||||
parser.parse(ddl, tables);
|
||||
parser.parse(ddl2, tables);
|
||||
assertThat(tables.size()).isEqualTo(2);
|
||||
Table foo = tables.forTable(new TableId(null, null, "fooView"));
|
||||
assertThat(foo).isNotNull();
|
||||
assertThat(foo.columnNames()).containsExactly("c1", "c2");
|
||||
assertThat(foo.primaryKeyColumnNames()).isEmpty();
|
||||
assertColumn(foo, "c1", "INTEGER", Types.INTEGER, -1, -1, false, true, true);
|
||||
assertColumn(foo, "c2", "VARCHAR", Types.VARCHAR, 22, -1, true, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseDropView() {
|
||||
String ddl = "CREATE TABLE foo ( " + System.lineSeparator()
|
||||
+ " c1 INTEGER NOT NULL AUTO_INCREMENT, " + System.lineSeparator()
|
||||
+ " c2 VARCHAR(22) " + System.lineSeparator()
|
||||
+ "); " + System.lineSeparator();
|
||||
String ddl2 = "CREATE VIEW fooView AS (SELECT * FROM foo)" + System.lineSeparator();
|
||||
String ddl3 = "DROP VIEW fooView";
|
||||
parser = new MysqlDdlParserWithSimpleTestListener(listener, true);
|
||||
parser.parse(ddl, tables);
|
||||
parser.parse(ddl2, tables);
|
||||
parser.parse(ddl3, tables);
|
||||
assertThat(tables.size()).isEqualTo(1);
|
||||
Table foo = tables.forTable(new TableId(null, null, "fooView"));
|
||||
assertThat(foo).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseCreateViewStatementColumnAlias() {
|
||||
String ddl = "CREATE TABLE foo ( " + System.lineSeparator()
|
||||
+ " c1 INTEGER NOT NULL AUTO_INCREMENT, " + System.lineSeparator()
|
||||
+ " c2 VARCHAR(22) " + System.lineSeparator()
|
||||
+ "); " + System.lineSeparator();
|
||||
String ddl2 = "CREATE VIEW fooView(w1) AS (SELECT c2 as w1 FROM foo)" + System.lineSeparator();
|
||||
|
||||
parser = new MysqlDdlParserWithSimpleTestListener(listener, true);
|
||||
parser.parse(ddl, tables);
|
||||
parser.parse(ddl2, tables);
|
||||
assertThat(tables.size()).isEqualTo(2);
|
||||
Table foo = tables.forTable(new TableId(null, null, "fooView"));
|
||||
assertThat(foo).isNotNull();
|
||||
assertThat(foo.columnNames()).containsExactly("w1");
|
||||
assertThat(foo.primaryKeyColumnNames()).isEmpty();
|
||||
assertColumn(foo, "w1", "VARCHAR", Types.VARCHAR, 22, -1, true, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseCreateViewStatementColumnAliasInnerSelect() {
|
||||
String ddl = "CREATE TABLE foo ( " + System.lineSeparator()
|
||||
+ " c1 INTEGER NOT NULL AUTO_INCREMENT, " + System.lineSeparator()
|
||||
+ " c2 VARCHAR(22) " + System.lineSeparator()
|
||||
+ "); " + System.lineSeparator();
|
||||
String ddl2 = "CREATE VIEW fooView(w1) AS (SELECT foo2.c2 as w1 FROM (SELECT c1 as c2 FROM foo) AS foo2)" + System.lineSeparator();
|
||||
|
||||
parser = new MysqlDdlParserWithSimpleTestListener(listener, true);
|
||||
parser.parse(ddl, tables);
|
||||
parser.parse(ddl2, tables);
|
||||
assertThat(tables.size()).isEqualTo(2);
|
||||
Table foo = tables.forTable(new TableId(null, null, "fooView"));
|
||||
assertThat(foo).isNotNull();
|
||||
assertThat(foo.columnNames()).containsExactly("w1");
|
||||
assertThat(foo.primaryKeyColumnNames()).isEmpty();
|
||||
assertColumn(foo, "w1", "INTEGER", Types.INTEGER, -1, -1, false, true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseAlterViewStatementColumnAliasInnerSelect() {
|
||||
String ddl = "CREATE TABLE foo ( " + System.lineSeparator()
|
||||
+ " c1 INTEGER NOT NULL AUTO_INCREMENT, " + System.lineSeparator()
|
||||
+ " c2 VARCHAR(22) " + System.lineSeparator()
|
||||
+ "); " + System.lineSeparator();
|
||||
String ddl2 = "CREATE VIEW fooView(w1) AS (SELECT foo2.c2 as w1 FROM (SELECT c1 as c2 FROM foo) AS foo2)" + System.lineSeparator();
|
||||
String ddl3 = "ALTER VIEW fooView AS (SELECT c2 FROM foo)";
|
||||
parser = new MysqlDdlParserWithSimpleTestListener(listener, true);
|
||||
parser.parse(ddl, tables);
|
||||
parser.parse(ddl2, tables);
|
||||
parser.parse(ddl3, tables);
|
||||
assertThat(tables.size()).isEqualTo(2);
|
||||
assertThat(listener.total()).isEqualTo(3);
|
||||
Table foo = tables.forTable(new TableId(null, null, "fooView"));
|
||||
assertThat(foo).isNotNull();
|
||||
assertThat(foo.columnNames()).containsExactly("c2");
|
||||
assertThat(foo.primaryKeyColumnNames()).isEmpty();
|
||||
assertColumn(foo, "c2", "VARCHAR", Types.VARCHAR, 22, -1, true, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseCreateTableStatementWithSingleGeneratedColumnAsPrimaryKey() {
|
||||
String ddl = "CREATE TABLE my.foo ( " + System.lineSeparator()
|
||||
@ -755,7 +851,9 @@ public void shouldParseTestStatements() {
|
||||
// legacy parser was signaling all created index
|
||||
// antlr is parsing only those, which will make any model changes
|
||||
int numberOfNonUniqueIndexesCreated = 2;
|
||||
assertThat(listener.total()).isEqualTo(58 - numberOfAlteredTablesWhichDoesNotExists - numberOfNonUniqueIndexesCreated);
|
||||
int numberOfAlterViewStatements = 6;
|
||||
assertThat(listener.total()).isEqualTo(58 - numberOfAlteredTablesWhichDoesNotExists
|
||||
- numberOfNonUniqueIndexesCreated + numberOfAlterViewStatements);
|
||||
listener.forEach(this::printEvent);
|
||||
}
|
||||
|
||||
@ -1563,7 +1661,11 @@ protected void assertColumn(Table table, String name, String typeName, int jdbcT
|
||||
|
||||
class MysqlDdlParserWithSimpleTestListener extends MySqlAntlrDdlParser {
|
||||
public MysqlDdlParserWithSimpleTestListener(DdlChanges changesListener) {
|
||||
super(false);
|
||||
this(changesListener, false);
|
||||
}
|
||||
|
||||
public MysqlDdlParserWithSimpleTestListener(DdlChanges changesListener, boolean includeViews) {
|
||||
super(false, includeViews);
|
||||
this.ddlChanges = changesListener;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user