DBZ-252 test fixes + grammar fixes + some bug repairs in antlr parser

This commit is contained in:
rkuchar 2018-04-21 10:56:54 +02:00 committed by Gunnar Morling
parent 1124f81d94
commit 07212043b5
18 changed files with 380 additions and 233 deletions

View File

@ -228,6 +228,8 @@ protected void parseSetVariable(Marker start, AtomicReference<MySqlScope> scope)
}
systemVariables.setVariable(scope.get(), "character_set_client", charsetName);
systemVariables.setVariable(scope.get(), "character_set_results", charsetName);
systemVariables.setVariable(MySqlScope.SESSION, MySqlSystemVariables.CHARSET_NAME_CONNECTION,
systemVariables.getVariable(MySqlSystemVariables.CHARSET_NAME_DATABASE));
// systemVariables.setVariable(scope.get(), "collation_connection", ...);
} else if (tokens.canConsume("NAMES")) {
// https://dev.mysql.com/doc/refman/5.7/en/set-statement.html

View File

@ -28,6 +28,7 @@
import io.debezium.relational.TableId;
import io.debezium.relational.Tables;
import io.debezium.relational.ddl.DdlChanges;
import io.debezium.relational.ddl.DdlParser;
import io.debezium.relational.ddl.DdlParserListener.Event;
import io.debezium.relational.ddl.SimpleDdlParserListener;
import io.debezium.util.IoUtil;
@ -36,7 +37,7 @@
public class MySqlDdlParserTest {
private MySqlDdlParser parser;
private DdlParser parser;
private Tables tables;
private SimpleDdlParserListener listener;
@ -284,7 +285,7 @@ public void shouldParseCreateDatabaseAndTableThatUsesDefaultCharacterSets() {
+ "CREATE TABLE t1 (" + System.lineSeparator()
+ " id int(11) not null auto_increment," + System.lineSeparator()
+ " c1 varchar(255) default null," + System.lineSeparator()
+ " c2 varchar(255) charset default not null," + System.lineSeparator()
+ " c2 varchar(255) not null," + System.lineSeparator()
+ " c3 varchar(255) charset latin2 not null," + System.lineSeparator()
+ " primary key ('id')" + System.lineSeparator()
+ ") engine=InnoDB auto_increment=1006 default charset=latin1;" + System.lineSeparator();
@ -305,7 +306,7 @@ public void shouldParseCreateDatabaseAndTableThatUsesDefaultCharacterSets() {
ddl = "CREATE TABLE t2 (" + System.lineSeparator()
+ " id int(11) not null auto_increment," + System.lineSeparator()
+ " c1 varchar(255) default null," + System.lineSeparator()
+ " c2 varchar(255) charset default not null," + System.lineSeparator()
+ " c2 varchar(255) not null," + System.lineSeparator()
+ " c3 varchar(255) charset latin2 not null," + System.lineSeparator()
+ " primary key ('id')" + System.lineSeparator()
+ ") engine=InnoDB auto_increment=1006;" + System.lineSeparator();
@ -384,20 +385,21 @@ public void shouldParseSetCharacterSetStatement() {
assertVariable("character_set_connection", null);
assertVariable("character_set_database", null);
parser.parse("CREATE DATABASE db1 CHARACTER SET cs1;", tables);
parser.parse("CREATE DATABASE db1 CHARACTER SET LATIN1;", tables);
assertVariable("character_set_server", "utf8");
assertVariable("character_set_database", null); // changes when we USE a different database
parser.parse("USE db1;", tables);// changes the "character_set_database" system variable ...
assertVariable("character_set_server", "utf8");
assertVariable("character_set_database", "cs1");
assertVariable("character_set_connection", null);
assertVariable("character_set_database", "LATIN1");
parser.parse("SET CHARSET default;", tables);
assertVariable("character_set_server", "utf8");
assertVariable("character_set_client", "cs1");
assertVariable("character_set_results", "cs1");
assertVariable("character_set_connection", null);
assertVariable("character_set_database", "cs1");
assertVariable("character_set_client", "LATIN1");
assertVariable("character_set_results", "LATIN1");
assertVariable("character_set_connection", "LATIN1");
assertVariable("character_set_database", "LATIN1");
}
@Test
@ -429,20 +431,20 @@ public void shouldParseSetNamesStatement() {
assertVariable("character_set_connection", "utf16");
assertVariable("character_set_database", null);
parser.parse("CREATE DATABASE db1 CHARACTER SET cs1;", tables);
parser.parse("CREATE DATABASE db1 CHARACTER SET LATIN1;", tables);
assertVariable("character_set_server", "utf8");
assertVariable("character_set_database", null); // changes when we USE a different database
parser.parse("USE db1;", tables);// changes the "character_set_database" system variable ...
assertVariable("character_set_server", "utf8");
assertVariable("character_set_database", "cs1");
assertVariable("character_set_database", "LATIN1");
parser.parse("SET NAMES default;", tables);
assertVariable("character_set_server", "utf8");
assertVariable("character_set_client", "cs1");
assertVariable("character_set_results", "cs1");
assertVariable("character_set_connection", "cs1");
assertVariable("character_set_database", "cs1");
assertVariable("character_set_client", "LATIN1");
assertVariable("character_set_results", "LATIN1");
assertVariable("character_set_connection", "LATIN1");
assertVariable("character_set_database", "LATIN1");
}
@Test
@ -526,7 +528,7 @@ public void shouldParseCreateTableWithEnumAndSetColumns() {
@Test
public void shouldParseDefiner() {
String function = "FUNCTION fnA( a int, b int ) RETURNS tinyint(1) begin anything end;";
String function = "FUNCTION fnA( a int, b int ) RETURNS tinyint(1) begin -- anything end;";
String ddl = "CREATE DEFINER='mysqluser'@'%' " + function;
parser.parse(ddl, tables);
assertThat(tables.size()).isEqualTo(0); // no tables
@ -699,23 +701,23 @@ public void shouldParseSetOfSessionVariable() {
@Test
public void shouldParseButNotSetUserVariableWithHyphenDelimiter() {
String ddl = "SET @a-b-c-d:=1";
String ddl = "SET @a_b_c_d:=1";
parser.parse(ddl, tables);
assertLocalVariable("a-b-c-d", null);
assertSessionVariable("a-b-c-d", null);
assertGlobalVariable("a-b-c-d", null);
assertLocalVariable("a_b_c_d", null);
assertSessionVariable("a_b_c_d", null);
assertGlobalVariable("a_b_c_d", null);
}
@Test
public void shouldParseVariableWithHyphenDelimiter() {
String ddl = "SET a-b-c-d=1";
String ddl = "SET a_b_c_d=1";
parser.parse(ddl, tables);
assertSessionVariable("a-b-c-d", "1");
assertSessionVariable("a_b_c_d", "1");
}
@Test
public void shouldParseAndIgnoreDeleteStatements() {
String ddl = "DELETE FROM blah blah";
String ddl = "DELETE FROM blah";
parser.parse(ddl, tables);
assertThat(tables.size()).isEqualTo(0);
assertThat(listener.total()).isEqualTo(0);
@ -723,7 +725,7 @@ public void shouldParseAndIgnoreDeleteStatements() {
@Test
public void shouldParseAndIgnoreInsertStatements() {
String ddl = "INSERT INTO blah blah";
String ddl = "INSERT INTO blah (id) values (1)";
parser.parse(ddl, tables);
assertThat(tables.size()).isEqualTo(0);
assertThat(listener.total()).isEqualTo(0);
@ -778,7 +780,7 @@ public void shouldParseTestStatements() {
parser.parse(readFile("ddl/mysql-test-statements.ddl"), tables);
Testing.print(tables);
assertThat(tables.size()).isEqualTo(6);
assertThat(listener.total()).isEqualTo(61);
assertThat(listener.total()).isEqualTo(58);
listener.forEach(this::printEvent);
}
@ -1025,7 +1027,7 @@ public void shouldParseStatementForDbz200() {
"ISDEFAULT", "ISREQUIRED", "NAME", "VALUES", "AMOUNTS", "DESCRIPTION",
"TYPE", "VALUELENGTH", "INDEXINLIST", "CUSTOMFIELDSET_ENCODEDKEY_OID",
"STATE", "VALIDATIONPATTERN", "VIEWUSAGERIGHTSKEY", "EDITUSAGERIGHTSKEY",
"BUILTINCUSTOMFIELDID", "UNIQUE");
"BUILTINCUSTOMFIELDID", "UNIQUE", "STORAGE");
assertColumn(t, "ENCODEDKEY", "VARCHAR", Types.VARCHAR, 32, -1, false, false, false);
assertColumn(t, "ID", "VARCHAR", Types.VARCHAR, 32, -1, true, false, false);
assertColumn(t, "CREATIONDATE", "DATETIME", Types.TIMESTAMP, -1, -1, true, false, false);
@ -1047,6 +1049,7 @@ public void shouldParseStatementForDbz200() {
assertColumn(t, "EDITUSAGERIGHTSKEY", "VARCHAR", Types.VARCHAR, 32, -1, true, false, false);
assertColumn(t, "BUILTINCUSTOMFIELDID", "VARCHAR", Types.VARCHAR, 255, -1, true, false, false);
assertColumn(t, "UNIQUE", "VARCHAR", Types.VARCHAR, 32, -1, false, false, false);
assertColumn(t, "STORAGE", "VARCHAR", Types.VARCHAR, 32, -1, false, false, false);
assertThat(t.columnWithName("ENCODEDKEY").position()).isEqualTo(1);
assertThat(t.columnWithName("id").position()).isEqualTo(2);
assertThat(t.columnWithName("CREATIONDATE").position()).isEqualTo(3);
@ -1481,7 +1484,7 @@ public void parseUserDdlStatements() {
public void parsePartitionReorganize() {
String ddl =
"CREATE TABLE flat_view_request_log (id INT NOT NULL, myvalue INT DEFAULT -10, PRIMARY KEY (`id`));"
+ "ALTER TABLE flat_view_request_log REORGANIZE PARTITION p_max INTO ( PARTITION p_2018_01_17 VALUES LESS THAN ('2018-01-17'), PARTITION p_2018_01_18 VALUES LESS THAN ('2018-01-18'), PARTITION p_max VALUES LESS THAN MAXVALUE);";
+ "ALTER TABLE flat_view_request_log REORGANIZE PARTITION p_max INTO ( PARTITION p_2018_01_17 VALUES LESS THAN ('2018-01-17'), PARTITION p_2018_01_18 VALUES LESS THAN ('2018-01-18'), PARTITION p_max VALUES LESS THAN (MAXVALUE));";
parser.parse(ddl, tables);
assertThat(tables.size()).isEqualTo(1);
}
@ -1632,6 +1635,7 @@ protected void assertColumn(Table table, String name, String typeName, int jdbcT
class MysqlDdlParserWithSimpleTestListener extends MySqlDdlParser {
public MysqlDdlParserWithSimpleTestListener(DdlChanges changesListener) {
// super(false);
super();
this.ddlChanges = changesListener;
}

View File

@ -41,6 +41,6 @@ BEGIN
DECLARE i int default 0;
doubleNestedBegin: BEGIN
DECLARE i int default 0;
END doubleNestedBegin
END
END doubleNestedBegin;
END;
END

View File

@ -1,4 +1,4 @@
--ONE DDL TEST CASE FOR FUNCTION
-- ONE DDL TEST CASE FOR FUNCTION
CREATE DEFINER=`root`@`localhost` FUNCTION `ROUND_OFF`(IN_VAL DOUBLE,TECHNIQUE INT,PRECESSION_VAL INT) RETURNS double
DETERMINISTIC

View File

@ -1,4 +1,4 @@
--ONE DDL TEST CASE FOR FUNCTION
-- ONE DDL TEST CASE FOR FUNCTION
CREATE DEFINER=`root`@`localhost` FUNCTION `ROUND_OFF`(IN_VAL DOUBLE,TECHNIQUE INT,PRECESSION_VAL INT) RETURNS double
DETERMINISTIC

View File

@ -1,4 +1,4 @@
--ONE DDL TEST CASE FOR PROCEDURE WITH CURSOR
-- ONE DDL TEST CASE FOR PROCEDURE WITH CURSOR
CREATE DEFINER=`parasshah`@`%` PROCEDURE `SP_GETCHILDBYID`(GIVEN_ID INT,GIVEN_EXAM_ID INT)
BEGIN
DECLARE done INT DEFAULT 0;

View File

@ -1,4 +1,4 @@
--ONE more DDL TEST CASE FOR FUNCTION
-- ONE more DDL TEST CASE FOR FUNCTION
CREATE DEFINER=`kiranb`@`%` FUNCTION `CHECK_FOR_BED_ALLOCATED`(BRANCHID BIGINT, STUDENTID BIGINT) RETURNS varchar(255) CHARSET utf8
DETERMINISTIC
BEGIN

View File

@ -14,6 +14,6 @@ create table `NextTimeTable`.`TIMETABLE_SUBJECT_GROUP_MAPPING` (
Alter table `NextTimeTable`.`TIMETABLE_SUBJECT_GROUP_MAPPING`
drop column `SUBJECT_ID`,
drop index `FK69atxmt7wrwpb4oekyravsx9l`,
drop foreign key `FK69atxmt7wrwpb4oekyravsx9l`
drop foreign key `FK69atxmt7wrwpb4oekyravsx9l`;
create table `db1`.`table1` ( pk1 int not null, `id` int not null, `other` int );

View File

@ -19,6 +19,7 @@ CREATE TABLE `customfield` (
`VIEWUSAGERIGHTSKEY` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`EDITUSAGERIGHTSKEY` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`BUILTINCUSTOMFIELDID` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
UNIQUE varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`UNIQUE` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
STORAGE varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
KEY `index1` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -1074,7 +1074,7 @@ CREATE OR REPLACE VIEW MMR_FEATURE_VALUES AS
NULL AS FLOAT_VALUE,
NULL AS INT_VALUE,
NULL AS LONG_VALUE,
NULL AS SHORT_VALUE,0
NULL AS SHORT_VALUE,
NULL AS STRING_VALUE,
VALUE AS CLOB_VALUE,
NULL AS ENUM_ID,

View File

@ -7,9 +7,9 @@ RENAME TABLE blue_table TO red_table,
orange_table TO green_table,
black_table TO white_table;
RENAME DATABASE blue_db TO red_db;
-- RENAME DATABASE blue_db TO red_db;
RENAME SCHEMA blue_schema TO red_schema;
-- RENAME SCHEMA blue_schema TO red_schema;
CREATE TABLE RT_VDB_MDLS
(
@ -152,7 +152,7 @@ CREATE EVENT myevent
DO
UPDATE myschema.mytable SET mycol = mycol + 1;
--ALTER
-- ALTER
-- [DEFINER = { user | CURRENT_USER }]
-- EVENT event_name
-- [ON SCHEDULE schedule]
@ -182,7 +182,7 @@ ALTER EVENT myevent
ALTER EVENT olddb.myevent
RENAME TO newdb.myevent;
--ALTER LOGFILE GROUP logfile_group
-- ALTER LOGFILE GROUP logfile_group
-- ADD UNDOFILE 'file_name'
-- [INITIAL_SIZE [=] size]
-- [WAIT]
@ -193,9 +193,9 @@ ALTER LOGFILE GROUP lg_3
INITIAL_SIZE=32M
ENGINE=NDBCLUSTER;
--ALTER FUNCTION func_name [characteristic ...]
-- ALTER FUNCTION func_name [characteristic ...]
--
--characteristic:
-- characteristic:
-- { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
-- | SQL SECURITY { DEFINER | INVOKER }
-- | COMMENT 'string'
@ -214,15 +214,15 @@ ALTER PROCEDURE fall_back COMMENT 'no more wind please';
ALTER SERVER s OPTIONS (USER 'sally');
--ALTER TABLESPACE tablespace_name
-- ALTER TABLESPACE tablespace_name
-- {ADD|DROP} DATAFILE 'file_name'
-- [INITIAL_SIZE [=] size]
-- [WAIT]
-- ENGINE [=] engine_name
ALTER TABLESPACE tspace_name ADD DATAFILE 'file_name'INITIAL_SIZE = 9999 WAIT;
ALTER TABLESPACE tspace_name ADD DATAFILE 'file_name'INITIAL_SIZE = 9999 WAIT ENGINE = MEMORY;
--ALTER
-- ALTER
-- [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
-- [DEFINER = { user | CURRENT_USER }]
-- [SQL SECURITY { DEFINER | INVOKER }]
@ -234,18 +234,18 @@ ALTER VIEW great_view (c1, c2) AS SELECT * FROM table_a;
ALTER VIEW great_view (c1, c2) AS SELECT * FROM table_a WITH LOCAL CHECK OPTION;
ALTER VIEW ALGORITHM = MERGE great_view AS SELECT * FROM table_a;
ALTER ALGORITHM = MERGE VIEW great_view AS SELECT * FROM table_a;
ALTER VIEW DEFINER = 'joe'@'there.com' great_view AS SELECT * FROM table_a;
ALTER DEFINER = 'joe'@'there.com' VIEW great_view AS SELECT * FROM table_a;
-- ============ 50 STATEMENTS ====================
ALTER VIEW SQL SECURITY INVOKER great_view AS SELECT * FROM table_a;
ALTER SQL SECURITY INVOKER VIEW great_view AS SELECT * FROM table_a;
ALTER VIEW ALGORITHM = MERGE DEFINER = 'joe'@'there.com' SQL SECURITY INVOKER great_view AS SELECT * FROM table_a;
ALTER ALGORITHM = MERGE DEFINER = 'joe'@'there.com' SQL SECURITY INVOKER VIEW great_view AS SELECT * FROM table_a;
--CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
-- CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
-- [create_specification] ...
--
--create_specification:
-- create_specification:
-- [DEFAULT] CHARACTER SET [=] charset_name
-- | [DEFAULT] COLLATE [=] collation_name
@ -253,7 +253,7 @@ CREATE DATABASE db_1;
CREATE DATABASE db_2 DEFAULT CHARACTER SET = utf8;
CREATE DATABASE db_3 CHARACTER SET utf10;
CREATE DATABASE db_3 CHARACTER SET utf16;
CREATE DATABASE IF NOT EXISTS db_4 DEFAULT CHARACTER SET = utf8;
@ -261,7 +261,7 @@ CREATE SCHEMA schema_1;
CREATE SCHEMA schema_2 DEFAULT CHARACTER SET = utf8;
CREATE SCHEMA schema_3 CHARACTER SET utf10;
CREATE SCHEMA schema_3 CHARACTER SET utf16;
CREATE SCHEMA IF NOT EXISTS schema_4 DEFAULT CHARACTER SET = utf8;
-- ============ 60 STATEMENTS ====================
@ -271,21 +271,21 @@ CREATE INDEX id_index USING BTREE ON lookup (id);
-- CREATE [ONLINE|OFFLINE] [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
CREATE ONLINE INDEX index_1;
# CREATE ONLINE INDEX index_1;
#
# CREATE OFFLINE INDEX index_2;
#
# CREATE ONLINE UNIQUE INDEX index_3;
#
# CREATE OFFLINE FULLTEXT INDEX index_4;
#
# CREATE UNIQUE INDEX index_5;
#
# CREATE FULLTEXT INDEX index_6;
#
# CREATE SPATIAL INDEX index_7;
CREATE OFFLINE INDEX index_2;
CREATE ONLINE UNIQUE INDEX index_3;
CREATE OFFLINE FULLTEXT INDEX index_4;
CREATE UNIQUE INDEX index_5;
CREATE FULLTEXT INDEX index_6;
CREATE SPATIAL INDEX index_7;
--CREATE LOGFILE GROUP lf_group_name
-- CREATE LOGFILE GROUP lf_group_name
-- ADD UNDOFILE 'undo_file'
-- [INITIAL_SIZE [=] initial_size]
-- [UNDO_BUFFER_SIZE [=] undo_buffer_size]
@ -296,18 +296,18 @@ CREATE SPATIAL INDEX index_7;
-- ENGINE [=] engine_name
CREATE LOGFILE GROUP lf_group_name_1 ADD UNDOFILE 'my_undo_file'
ENGINE some_engine_name;
ENGINE NDB;
-- ============ 70 STATEMENTS ====================
CREATE LOGFILE GROUP lf_group_name_2 ADD UNDOFILE 'my_undo_file'
INITIAL_SIZE = 9999 WAIT COMMENT = 'some bogus comment'
ENGINE some_engine_name;
ENGINE NDB;
CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
BEGIN
SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
END;
CREATE DEFINER = 'admin'@'localhost' FUNCTION account_count()
CREATE DEFINER = 'admin'@'localhost' FUNCTION account_count() RETURNS INT
SQL SECURITY INVOKER
BEGIN
SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
@ -317,7 +317,7 @@ CREATE SERVER server_1
FOREIGN DATA WRAPPER mysql
OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
--CREATE TABLESPACE tablespace_name
-- CREATE TABLESPACE tablespace_name
-- ADD DATAFILE 'file_name'
-- USE LOGFILE GROUP logfile_group
-- [EXTENT_SIZE [=] extent_size]
@ -329,10 +329,9 @@ CREATE SERVER server_1
-- [COMMENT [=] comment_text]
-- ENGINE [=] engine_name
CREATE TABLESPACE tbl_space_1 ADD DATAFILE 'my_data_file' USER LOGFILE GROUP my_lf_group
ENGINE = my_engine_1;
CREATE TABLESPACE tbl_space_1 ADD DATAFILE 'my_data_file' USER LOGFILE GROUP my_lf_group ENGINE = NDB;
--CREATE
-- CREATE
-- [DEFINER = { user | CURRENT_USER }]
-- TRIGGER trigger_name trigger_time trigger_event
-- ON tbl_name FOR EACH ROW trigger_stmt
@ -347,14 +346,14 @@ CREATE TRIGGER testref BEFORE INSERT ON test1
UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
END;
CREATE DEFINER = 'user'@'hostname' TRIGGER my_trigger_1 INSERT ON test1
CREATE DEFINER = 'user'@'hostname' TRIGGER my_trigger_1 BEFORE INSERT ON test1
FOR EACH ROW BEGIN
INSERT INTO test2 SET a2 = NEW.a1;
DELETE FROM test3 WHERE a3 = NEW.a1;
UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
END;
--CREATE
-- CREATE
-- [OR REPLACE]
-- [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
-- [DEFINER = { user | CURRENT_USER }]
@ -395,7 +394,7 @@ DROP SERVER my_server_1;
DROP SERVER IF EXISTS my_server_2;
--DROP [TEMPORARY] TABLE [IF EXISTS]
-- DROP [TEMPORARY] TABLE [IF EXISTS]
-- tbl_name [, tbl_name] ...
-- [RESTRICT | CASCADE]
@ -409,12 +408,12 @@ DROP TABLE IF EXISTS table_4, table_5, table_6;
DROP TABLE IF EXISTS table_7, table_8 RESTRICT;
--DROP TABLESPACE tablespace_name
-- DROP TABLESPACE tablespace_name
-- ENGINE [=] engine_name
DROP TABLESPACE my_tbl_space_1 ENGINE = my_eng;
DROP TABLESPACE my_tbl_space_1 ENGINE = NDB;
DROP TABLESPACE my_tbl_space_2 ENGINE my_eng;
DROP TABLESPACE my_tbl_space_2 ENGINE NDB;
-- ============ 100 STATEMENTS ====================
DROP TRIGGER my_schema_1.blue_trigger;

View File

@ -177,8 +177,11 @@ public void removeTablesForDatabase(String catalogName, String schemaName) {
lock.write(() -> {
tablesByTableId.entrySet().removeIf(tableIdTableEntry -> {
TableId tableId = tableIdTableEntry.getKey();
return (schemaName == null || tableId.schema() == null || schemaName.equals(tableId.schema()))
& (catalogName == null || tableId.catalog() == null || catalogName.equals(tableId.catalog()));
boolean equalSchema = schemaName == null && tableId.schema() == null
|| schemaName != null && schemaName.equals(tableId.schema());
boolean equalCatalog = catalogName == null && tableId.catalog() == null
|| catalogName != null && catalogName.equals(tableId.schema());
return equalSchema && equalCatalog;
});
});
}

View File

@ -36,7 +36,7 @@ SPACE: [ \t\r\n]+ -> channel(HIDDEN);
SPEC_MYSQL_COMMENT: '/*!' .+? '*/' -> channel(MYSQLCOMMENT);
COMMENT_INPUT: '/*' .*? '*/' -> channel(HIDDEN);
LINE_COMMENT: (
('-- ' | '#') ~[\r\n]* ('\r'? '\n' | EOF)
('-- ' | '#') ~[\r\n]* ('\r'? '\n' | EOF)
| '--' ('\r'? '\n' | EOF)
) -> channel(HIDDEN);
@ -336,6 +336,7 @@ CHAIN: 'CHAIN';
CHANGED: 'CHANGED';
CHANNEL: 'CHANNEL';
CHECKSUM: 'CHECKSUM';
PAGE_CHECKSUM: 'PAGE_CHECKSUM';
CIPHER: 'CIPHER';
CLIENT: 'CLIENT';
CLOSE: 'CLOSE';
@ -703,7 +704,7 @@ MRG_MYISAM: 'MRG_MYISAM';
MYISAM: 'MYISAM';
NDB: 'NDB';
NDBCLUSTER: 'NDBCLUSTER';
PERFOMANCE_SCHEMA: 'PERFOMANCE_SCHEMA';
PERFORMANCE_SCHEMA: 'PERFORMANCE_SCHEMA';
// Transaction Levels
@ -1099,7 +1100,7 @@ FILESIZE_LITERAL: DEC_DIGIT+ ('K'|'M'|'G'|'T');
START_NATIONAL_STRING_LITERAL: 'N' SQUOTA_STRING;
STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING;
DECIMAL_LITERAL: DEC_DIGIT+;
DECIMAL_LITERAL: '-'? DEC_DIGIT+;
HEXADECIMAL_LITERAL: 'X' '\'' (HEX_DIGIT HEX_DIGIT)+ '\''
| '0X' HEX_DIGIT+;

View File

@ -37,7 +37,7 @@ root
;
sqlStatements
: (sqlStatement MINUSMINUS? SEMI | emptyStatement)*
: (sqlStatement MINUSMINUS? SEMI | emptyStatement)*
(sqlStatement (MINUSMINUS? SEMI)? | emptyStatement)
;
@ -304,7 +304,7 @@ indexOption
;
procedureParameter
: direction=(IN | OUT | INOUT) uid dataType
: direction=(IN | OUT | INOUT)? uid dataType
;
functionParameter
@ -349,18 +349,20 @@ columnDefinition
columnConstraint
: nullNotnull #nullColumnConstraint
| DEFAULT defaultValue #defaultColumnConstraint
| AUTO_INCREMENT #autoIncrementColumnConstraint
| (AUTO_INCREMENT | ON UPDATE timeDefinition) #autoIncrementColumnConstraint
| PRIMARY? KEY #primaryKeyColumnConstraint
| UNIQUE KEY? #uniqueKeyColumnConstraint
| COMMENT STRING_LITERAL #commentColumnConstraint
| COLUMN_FORMAT colformat=(FIXED | DYNAMIC | DEFAULT) #formatColumnConstraint
| STORAGE storageval=(DISK | MEMORY | DEFAULT) #storageColumnConstraint
| referenceDefinition #referenceColumnConstraint
| COLLATE collationName #collateColumnConstraint
;
tableConstraint
: (CONSTRAINT name=uid?)?
PRIMARY KEY indexType? indexColumnNames indexOption* #primaryKeyTableConstraint
PRIMARY KEY index=uid? indexType?
indexColumnNames indexOption* #primaryKeyTableConstraint
| (CONSTRAINT name=uid?)?
UNIQUE indexFormat=(INDEX | KEY)? index=uid?
indexType? indexColumnNames indexOption* #uniqueKeyTableConstraint
@ -371,7 +373,7 @@ tableConstraint
;
referenceDefinition
: REFERENCES tableName indexColumnNames
: REFERENCES tableName indexColumnNames?
(MATCH matchType=(FULL | PARTIAL | SIMPLE))?
referenceAction?
;
@ -404,7 +406,7 @@ tableOption
| AUTO_INCREMENT '='? decimalLiteral #tableOptionAutoIncrement
| AVG_ROW_LENGTH '='? decimalLiteral #tableOptionAverage
| DEFAULT? (CHARACTER SET | CHARSET) '='? charsetName #tableOptionCharset
| CHECKSUM '='? boolValue=('0' | '1') #tableOptionChecksum
| (CHECKSUM | PAGE_CHECKSUM) '='? boolValue=('0' | '1') #tableOptionChecksum
| DEFAULT? COLLATE '='? collationName #tableOptionCollate
| COMMENT '='? STRING_LITERAL #tableOptionComment
| COMPRESSION '='? STRING_LITERAL #tableOptionCompression
@ -428,6 +430,7 @@ tableOption
| STATS_PERSISTENT '='? extBoolValue=(DEFAULT | '0' | '1') #tableOptionPersistent
| STATS_SAMPLE_PAGES '='? decimalLiteral #tableOptionSamplePage
| TABLESPACE uid tablespaceStorage? #tableOptionTablespace
| tablespaceStorage #tableOptionTablespace
| UNION '='? '(' tables ')' #tableOptionUnion
;
@ -440,7 +443,7 @@ partitionDefinitions
(PARTITIONS count=decimalLiteral)?
(
SUBPARTITION BY subpartitionFunctionDefinition
(SUBPARTITIONS subCount=decimalLiteral)?
(SUBPARTITIONS subCount=decimalLiteral)?
)?
('(' partitionDefinition (',' partitionDefinition)* ')')?
;
@ -461,11 +464,14 @@ subpartitionFunctionDefinition
partitionDefinition
: PARTITION uid VALUES LESS THAN
'('
'('
partitionDefinerAtom (',' partitionDefinerAtom)*
')'
partitionOption*
(subpartitionDefinition (',' subpartitionDefinition)*)? #partitionComparision
| PARTITION uid VALUES LESS THAN
partitionDefinerAtom partitionOption*
(subpartitionDefinition (',' subpartitionDefinition)*)? #partitionComparision
| PARTITION uid VALUES IN
'('
partitionDefinerAtom (',' partitionDefinerAtom)*
@ -483,7 +489,7 @@ partitionDefinition
;
partitionDefinerAtom
: constant | MAXVALUE | expression
: constant | expression | MAXVALUE
;
partitionDefinerVector
@ -551,7 +557,7 @@ alterServer
alterTable
: ALTER intimeAction=(ONLINE | OFFLINE)?
IGNORE? TABLE tableName
alterSpecification (',' alterSpecification)*
(alterSpecification (',' alterSpecification)*)?
partitionDefinitions?
;
@ -604,7 +610,7 @@ alterSpecification
| LOCK '='? lockType=(DEFAULT | NONE | SHARED | EXCLUSIVE) #alterByLock
| MODIFY COLUMN?
uid columnDefinition (FIRST | AFTER uid)? #alterByModifyColumn
| DROP COLUMN? uid #alterByDropColumn
| DROP COLUMN? uid RESTRICT? #alterByDropColumn
| DROP PRIMARY KEY #alterByDropPrimaryKey
| DROP indexFormat=(INDEX | KEY) uid #alterByDropIndex
| DROP FOREIGN KEY uid #alterByDropForeignKey
@ -1328,7 +1334,7 @@ blockStatement
(declareCondition SEMI)*
(declareCursor SEMI)*
(declareHandler SEMI)*
procedureSqlStatement+
(procedureSqlStatement)*
)?
END uid?
;
@ -1633,8 +1639,8 @@ uninstallPlugin
// Set and show statements
setStatement
: SET variableClause '=' expression
(',' variableClause '=' expression)* #setVariable
: SET variableClause ('=' | ':=') expression
(',' variableClause ('=' | ':=') expression)* #setVariable
| SET (CHARACTER SET | CHARSET) (charsetName | DEFAULT) #setCharset
| SET NAMES
(charsetName (COLLATE collationName)? | DEFAULT) #setNames
@ -1694,7 +1700,7 @@ showStatement
// details
variableClause
: LOCAL_ID | GLOBAL_ID | ( ('@' '@')? (GLOBAL | SESSION) )? uid
: LOCAL_ID | GLOBAL_ID | (('@' '@')? (GLOBAL | SESSION | LOCAL))? uid
;
showCommonEntity
@ -1847,11 +1853,11 @@ fullColumnName
;
indexColumnName
: uid ('(' decimalLiteral ')')? sortType=(ASC | DESC)?
: (uid | STRING_LITERAL) ('(' decimalLiteral ')')? sortType=(ASC | DESC)?
;
userName
: STRING_USER_NAME | ID;
: STRING_USER_NAME | ID | STRING_LITERAL;
mysqlVariable
: LOCAL_ID
@ -1870,7 +1876,7 @@ collationName
engineName
: ARCHIVE | BLACKHOLE | CSV | FEDERATED | INNODB | MEMORY
| MRG_MYISAM | MYISAM | NDB | NDBCLUSTER | PERFOMANCE_SCHEMA
| MRG_MYISAM | MYISAM | NDB | NDBCLUSTER | PERFORMANCE_SCHEMA
;
uuidSet
@ -1968,23 +1974,23 @@ dataType
| NCHAR | NVARCHAR
)
lengthOneDimension? BINARY?
(CHARACTER SET charsetName)? (COLLATE collationName)? #stringDataType
((CHARACTER SET | CHARSET) charsetName)? #stringDataType
| NATIONAL typeName=(VARCHAR | CHARACTER)
lengthOneDimension? BINARY? (COLLATE collationName)? #nationalStringDataType
lengthOneDimension? BINARY? #nationalStringDataType
| NCHAR typeName=VARCHAR
lengthOneDimension? BINARY? (COLLATE collationName)? #nationalStringDataType
lengthOneDimension? BINARY? #nationalStringDataType
| NATIONAL typeName=(CHAR | CHARACTER) VARYING
lengthOneDimension? BINARY? (COLLATE collationName)? #nationalVaryingStringDataType
lengthOneDimension? BINARY? #nationalVaryingStringDataType
| typeName=(
TINYINT | SMALLINT | MEDIUMINT | INT | INTEGER | BIGINT
)
lengthOneDimension? UNSIGNED? ZEROFILL? #dimensionDataType
lengthOneDimension? (SIGNED | UNSIGNED)? ZEROFILL? #dimensionDataType
| typeName=(REAL | FLOAT)
lengthTwoDimension? UNSIGNED? ZEROFILL? #dimensionDataType
lengthTwoDimension? (SIGNED | UNSIGNED)? ZEROFILL? #dimensionDataType
| typeName=DOUBLE PRECISION?
lengthTwoDimension? UNSIGNED? ZEROFILL? #dimensionDataType
lengthTwoDimension? (SIGNED | UNSIGNED)? ZEROFILL? #dimensionDataType
| typeName=(DECIMAL | DEC | FIXED | NUMERIC)
lengthTwoOptionalDimension? UNSIGNED? ZEROFILL? #dimensionDataType
lengthTwoOptionalDimension? (SIGNED | UNSIGNED)? ZEROFILL? #dimensionDataType
| typeName=(
DATE | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB
| BOOL | BOOLEAN
@ -1995,14 +2001,18 @@ dataType
)
lengthOneDimension? #dimensionDataType
| typeName=(ENUM | SET)
'(' STRING_LITERAL (',' STRING_LITERAL)* ')' BINARY?
(CHARACTER SET charsetName)? (COLLATE collationName)? #collectionDataType
'(' collectionOption (',' collectionOption)* ')' BINARY?
((CHARACTER SET | CHARSET) charsetName)? #collectionDataType
| typeName=(
GEOMETRYCOLLECTION | LINESTRING | MULTILINESTRING
| MULTIPOINT | MULTIPOLYGON | POINT | POLYGON | JSON | GEOMETRY
) #spatialDataType
;
collectionOption
: STRING_LITERAL
;
convertedDataType
: typeName=(BINARY| NCHAR) lengthOneDimension?
| typeName=CHAR lengthOneDimension? (CHARACTER SET charsetName)?
@ -2064,7 +2074,13 @@ userVariables
defaultValue
: NULL_LITERAL
| constant
| CURRENT_TIMESTAMP (ON UPDATE LOCALTIMESTAMP)?
// | timeDefinition (ON UPDATE timeDefinition)?
| timeDefinition
;
timeDefinition
: (CURRENT_TIMESTAMP | NOW | LOCALTIME | LOCALTIMESTAMP)
('(' functionArgs? ')')?
;
expressionOrDefault
@ -2337,7 +2353,7 @@ keywordsCanBeId
| AT | AUTHORS | AUTOCOMMIT | AUTOEXTEND_SIZE
| AUTO_INCREMENT | AVG_ROW_LENGTH | BEGIN | BINLOG | BIT
| BLOCK | BOOL | BOOLEAN | BTREE | CASCADED | CHAIN
| CHANNEL | CHECKSUM | CIPHER | CLIENT | COALESCE | CODE
| CHANNEL | CHECKSUM | PAGE_CHECKSUM | CIPHER | CLIENT | COALESCE | CODE
| COLUMNS | COLUMN_FORMAT | COMMENT | COMMIT | COMPACT
| COMPLETION | COMPRESSED | COMPRESSION | CONCURRENT
| CONNECTION | CONSISTENT | CONTAINS | CONTEXT
@ -2370,7 +2386,7 @@ keywordsCanBeId
| OJ | OLD_PASSWORD | ONE | ONLINE | ONLY | OPTIMIZER_COSTS
| OPTIONS | OWNER | PACK_KEYS | PAGE | PARSER | PARTIAL
| PARTITIONING | PARTITIONS | PASSWORD | PHASE | PLUGINS
| PLUGIN_DIR | PORT | PRECEDES | PREPARE | PRESERVE | PREV
| PLUGIN_DIR | PLUGIN | PORT | PRECEDES | PREPARE | PRESERVE | PREV
| PROCESSLIST | PROFILE | PROFILES | PROXY | QUERY | QUICK
| REBUILD | RECOVER | REDO_BUFFER_SIZE | REDUNDANT
| RELAYLOG | RELAY_LOG_FILE | RELAY_LOG_POS | REMOVE

View File

@ -10,6 +10,7 @@
import io.debezium.relational.Tables;
import io.debezium.relational.ddl.AbstractDdlParser;
import io.debezium.text.MultipleParsingExceptions;
import io.debezium.text.ParsingException;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CodePointCharStream;
@ -22,16 +23,22 @@
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.Collection;
/**
* @author Roman Kuchár <kucharrom@gmail.com>.
*/
public abstract class AntlrDdlParser<L extends Lexer, P extends Parser> extends AbstractDdlParser {
private boolean throwErrorsFromTreeWalk;
private ProxyParseTreeListener proxyParseTreeListener;
protected Tables databaseTables;
protected DataTypeResolver dataTypeResolver = new DataTypeResolver();
public AntlrDdlParser() {
public AntlrDdlParser(boolean throwErrorsFromTreeWalk) {
super(";");
this.throwErrorsFromTreeWalk = throwErrorsFromTreeWalk;
}
@Override
@ -53,12 +60,10 @@ public void parse(String ddlContent, Tables databaseTables) {
ParseTree parseTree = parseTree(parser);
if (parsingErrorListener.getErrors().isEmpty()) {
ProxyParseTreeListener proxyParseTreeListener = new ProxyParseTreeListener(this::accumulateParsingFailure);
assignParserListeners(proxyParseTreeListener);
proxyParseTreeListener = assignParserListeners();
ParseTreeWalker.DEFAULT.walk(proxyParseTreeListener, parseTree);
if (!proxyParseTreeListener.getErrors().isEmpty()) {
if (throwErrorsFromTreeWalk && !proxyParseTreeListener.getErrors().isEmpty()) {
throw new MultipleParsingExceptions(proxyParseTreeListener.getErrors());
}
}
@ -67,6 +72,10 @@ public void parse(String ddlContent, Tables databaseTables) {
}
}
public Collection<ParsingException> getParsingExceptionsFromWalker() {
return proxyParseTreeListener.getErrors();
}
/**
* Examine the supplied string containing DDL statements, and apply those statements to the specified
* database table definitions.
@ -75,7 +84,7 @@ public void parse(String ddlContent, Tables databaseTables) {
*/
protected abstract ParseTree parseTree(P parser);
protected abstract void assignParserListeners(ProxyParseTreeListener proxyParseTreeListener);
protected abstract ProxyParseTreeListener assignParserListeners();
/**
* Creates a new generic type instance of ANTLR Lexer.

View File

@ -34,6 +34,7 @@
public class ProxyParseTreeListener implements ParseTreeListener {
private List<ParseTreeListener> listeners;
private SkipException skipException = null;
private Collection<ParsingException> errors = new ArrayList<>();
private final BiFunction<ParsingException, Collection<ParsingException>, Collection<ParsingException>> accumulateError;
@ -58,28 +59,38 @@ public ProxyParseTreeListener(List<ParseTreeListener> listeners, BiFunction<Pars
@Override
public void enterEveryRule(ParserRuleContext ctx) {
for (ParseTreeListener listener : getListeners()) {
try {
listener.enterEveryRule(ctx);
ctx.enterRule(listener);
}
catch (ParsingException parsingException) {
accumulateError.apply(parsingException, errors);
if (skipException == null) {
for (ParseTreeListener listener : getListeners()) {
try {
listener.enterEveryRule(ctx);
ctx.enterRule(listener);
}
catch (ParsingException parsingException) {
accumulateError.apply(parsingException, errors);
}
catch (SkipException e) {
skipException = e;
}
}
}
}
@Override
public void exitEveryRule(ParserRuleContext ctx) {
for (ParseTreeListener listener : getListeners()) {
try {
ctx.exitRule(listener);
listener.exitEveryRule(ctx);
}
catch (ParsingException parsingException) {
accumulateError.apply(parsingException, errors);
if (skipException == null) {
for (ParseTreeListener listener : getListeners()) {
try {
ctx.exitRule(listener);
listener.exitEveryRule(ctx);
}
catch (ParsingException parsingException) {
accumulateError.apply(parsingException, errors);
}
}
}
else if (skipException.getCtxClass().isAssignableFrom(ctx.getClass())) {
skipException = null;
}
}
@Override

View File

@ -0,0 +1,25 @@
/*
* 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;
import org.antlr.v4.runtime.ParserRuleContext;
/**
* @author Roman Kuchár <kucharrom@gmail.com>.
*/
public class SkipException extends RuntimeException {
private Class<? extends ParserRuleContext> ctxClass;
public SkipException(Class<? extends ParserRuleContext> ctxClass) {
this.ctxClass = ctxClass;
}
public Class<? extends ParserRuleContext> getCtxClass() {
return ctxClass;
}
}

View File

@ -10,6 +10,7 @@
import io.debezium.antlr.DataTypeResolver;
import io.debezium.antlr.DataTypeResolver.DataTypeEntry;
import io.debezium.antlr.ProxyParseTreeListener;
import io.debezium.antlr.SkipException;
import io.debezium.antlr.mysql.MySqlSystemVariables.MySqlScope;
import io.debezium.ddl.parser.mysql.generated.MySqlLexer;
import io.debezium.ddl.parser.mysql.generated.MySqlParser;
@ -45,7 +46,11 @@ public class MySqlAntlrDdlParser extends AntlrDdlParser<MySqlLexer, MySqlParser>
private final ConcurrentMap<String, String> charsetNameForDatabase = new ConcurrentHashMap<>();
public MySqlAntlrDdlParser() {
super();
this(true);
}
public MySqlAntlrDdlParser(boolean throwErrorsFromTreeWalk) {
super(throwErrorsFromTreeWalk);
systemVariables = new MySqlSystemVariables();
}
@ -55,10 +60,11 @@ protected ParseTree parseTree(MySqlParser parser) {
}
@Override
protected void assignParserListeners(ProxyParseTreeListener proxyParseTreeListener) {
protected ProxyParseTreeListener assignParserListeners() {
ProxyParseTreeListener proxyParseTreeListener = new ProxyParseTreeListener(this::accumulateParsingFailure);
proxyParseTreeListener.add(new DatabaseOptionsListener());
proxyParseTreeListener.add(new DropDatabaseParserListener());
proxyParseTreeListener.add(new ColumnDefinitionParserListener());
proxyParseTreeListener.add(new DropDatabaseParserListener());
proxyParseTreeListener.add(new CreateTableParserListener());
proxyParseTreeListener.add(new AlterTableParserListener());
proxyParseTreeListener.add(new DropTableParserListener());
@ -68,6 +74,7 @@ protected void assignParserListeners(ProxyParseTreeListener proxyParseTreeListen
proxyParseTreeListener.add(new SetStatementParserListener());
proxyParseTreeListener.add(new UseStatementParserListener());
proxyParseTreeListener.add(new FinishSqlStatementParserListener());
return proxyParseTreeListener;
}
@Override
@ -93,12 +100,12 @@ protected boolean isGrammarInUpperCase() {
@Override
protected void initDataTypes(DataTypeResolver dataTypeResolver) {
dataTypeResolver.registerDataTypes(MySqlParser.StringDataTypeContext.class.getCanonicalName(), Arrays.asList(
new DataTypeEntry(MySqlParser.CHAR, Types.BINARY),
new DataTypeEntry(MySqlParser.CHAR, Types.CHAR),
new DataTypeEntry(MySqlParser.VARCHAR, Types.VARCHAR),
new DataTypeEntry(MySqlParser.TINYTEXT, Types.BLOB),
new DataTypeEntry(MySqlParser.TEXT, Types.BLOB),
new DataTypeEntry(MySqlParser.MEDIUMTEXT, Types.BLOB),
new DataTypeEntry(MySqlParser.LONGTEXT, Types.BLOB),
new DataTypeEntry(MySqlParser.TINYTEXT, Types.VARCHAR),
new DataTypeEntry(MySqlParser.TEXT, Types.VARCHAR),
new DataTypeEntry(MySqlParser.MEDIUMTEXT, Types.VARCHAR),
new DataTypeEntry(MySqlParser.LONGTEXT, Types.VARCHAR),
new DataTypeEntry(MySqlParser.NCHAR, Types.NCHAR),
new DataTypeEntry(MySqlParser.NVARCHAR, Types.NVARCHAR)
));
@ -158,8 +165,8 @@ protected void initDataTypes(DataTypeResolver dataTypeResolver) {
));
}
private TableId parseQualifiedTableId(MySqlParser.TableNameContext tableNameContext) {
String fullTableName = tableNameContext.fullId().getText();
private TableId parseQualifiedTableId(MySqlParser.FullIdContext fullIdContext) {
String fullTableName = fullIdContext.getText();
int dotIndex;
if ((dotIndex = fullTableName.indexOf(".")) > 0) {
return resolveTableId(withoutQuotes(fullTableName.substring(0, dotIndex)),
@ -186,10 +193,13 @@ private String getFullTableName(TableId tableId) {
private void resolveColumnDataType(MySqlParser.DataTypeContext dataTypeContext) {
String dataTypeName;
String charsetName = null;
Integer jdbcDataType = Types.NULL;
if (dataTypeContext instanceof MySqlParser.StringDataTypeContext) {
MySqlParser.StringDataTypeContext stringDataTypeContext = (MySqlParser.StringDataTypeContext) dataTypeContext;
dataTypeName = stringDataTypeContext.typeName.getText();
if (stringDataTypeContext.BINARY() != null) {
// TODO rkuchar: figure out something better
jdbcDataType = Types.BINARY;
dataTypeName += " " + stringDataTypeContext.BINARY().getText();
}
@ -238,6 +248,15 @@ else if (dataTypeContext instanceof MySqlParser.DimensionDataTypeContext) {
if (dimensionDataTypeContext.PRECISION() != null) {
dataTypeName += " " + dimensionDataTypeContext.PRECISION().getText();
}
if (dimensionDataTypeContext.SIGNED() != null) {
dataTypeName += " " + dimensionDataTypeContext.SIGNED().getText();
}
if (dimensionDataTypeContext.UNSIGNED() != null) {
dataTypeName += " " + dimensionDataTypeContext.UNSIGNED().getText();
}
if (dimensionDataTypeContext.ZEROFILL() != null) {
dataTypeName += " " + dimensionDataTypeContext.ZEROFILL().getText();
}
Integer length = null;
Integer scale = null;
@ -275,6 +294,13 @@ else if (dataTypeContext instanceof MySqlParser.CollectionDataTypeContext) {
charsetName = collectionDataTypeContext.charsetName().getText();
}
dataTypeName = collectionDataTypeContext.typeName.getText();
if (dataTypeName.equals("SET")) {
// After DBZ-132, it will always be comma seperated
columnEditor.length(Math.max(0, collectionDataTypeContext.collectionOption().size() * 2 - 1)); // number of options + number of commas
}
else {
columnEditor.length(1);
}
}
else if (dataTypeContext instanceof MySqlParser.SpatialDataTypeContext) {
dataTypeName = ((MySqlParser.SpatialDataTypeContext) dataTypeContext).typeName.getText();
@ -283,20 +309,26 @@ else if (dataTypeContext instanceof MySqlParser.SpatialDataTypeContext) {
throw new IllegalStateException("Not recognized instance of data type context for " + dataTypeContext.getText());
}
columnEditor.type(dataTypeName);
columnEditor.type(dataTypeName.toUpperCase());
if (charsetName != null) {
if (!"DEFAULT".equalsIgnoreCase(charsetName)) {
// Only record it if not inheriting the character set from the table
columnEditor.charsetName(charsetName);
if (jdbcDataType == Types.NULL) {
jdbcDataType = dataTypeResolver.resolveDataType(dataTypeContext);
}
columnEditor.jdbcType(jdbcDataType);
if (Types.DECIMAL == jdbcDataType) {
if (columnEditor.length() == -1) {
columnEditor.length(10);
}
if (columnEditor.scale() == -1) {
columnEditor.scale(0);
}
}
Integer jdbcDataType = dataTypeResolver.resolveDataType(dataTypeContext);
columnEditor.jdbcType(jdbcDataType);
if (Types.NCHAR == jdbcDataType || Types.NVARCHAR == jdbcDataType) {
// NCHAR and NVARCHAR columns always uses utf8 as charset
columnEditor.charsetName("utf8");
} else {
columnEditor.charsetName(charsetName);
}
}
@ -304,7 +336,13 @@ private void parsePrimaryIndexColumnNames(MySqlParser.IndexColumnNamesContext in
List<String> pkColumnNames = indexColumnNamesContext.indexColumnName().stream()
.map(indexColumnNameContext -> {
// MySQL does not allow a primary key to have nullable columns, so let's make sure we model that correctly ...
String columnName = parseName(indexColumnNameContext.uid());
String columnName;
if(indexColumnNameContext.uid() != null) {
columnName = parseName(indexColumnNameContext.uid());
}
else {
columnName = withoutQuotes(indexColumnNameContext.STRING_LITERAL().getText());
}
Column column = tableEditor.columnWithName(columnName);
if (column != null && column.isOptional()) {
tableEditor.addColumn(column.edit().optional(false).create());
@ -330,6 +368,61 @@ protected String currentDatabaseCharset() {
return charsetName;
}
/**
* Parser listener for MySQL column definition queries.
*/
private class ColumnDefinitionParserListener extends MySqlParserBaseListener {
@Override
public void enterColumnDefinition(MySqlParser.ColumnDefinitionContext ctx) {
runIfAllEditorsNotNull(() -> {
resolveColumnDataType(ctx.dataType());
});
super.enterColumnDefinition(ctx);
}
@Override
public void enterUniqueKeyColumnConstraint(MySqlParser.UniqueKeyColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> {
if (!tableEditor.hasPrimaryKey()) {
// take the first unique constrain if no primary key is set
tableEditor.addColumn(columnEditor.create());
tableEditor.setPrimaryKeyNames(columnEditor.name());
}
});
super.enterUniqueKeyColumnConstraint(ctx);
}
@Override
public void enterPrimaryKeyColumnConstraint(MySqlParser.PrimaryKeyColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> {
// this rule will be parsed only if no primary key is set in a table
// otherwise the statement can't be executed due to multiple primary key error
columnEditor.optional(false);
tableEditor.addColumn(columnEditor.create());
tableEditor.setPrimaryKeyNames(columnEditor.name());
});
super.enterPrimaryKeyColumnConstraint(ctx);
}
@Override
public void enterNullNotnull(MySqlParser.NullNotnullContext ctx) {
runIfAllEditorsNotNull(() -> columnEditor.optional(ctx.NOT() == null));
super.enterNullNotnull(ctx);
}
@Override
public void enterAutoIncrementColumnConstraint(MySqlParser.AutoIncrementColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> {
columnEditor.autoIncremented(true);
columnEditor.generated(true);
});
super.enterAutoIncrementColumnConstraint(ctx);
}
}
/**
* Parser listener for MySQL create database query to get database charsetName.
*/
@ -390,13 +483,17 @@ private class CreateTableParserListener extends MySqlParserBaseListener {
@Override
public void enterColumnCreateTable(MySqlParser.ColumnCreateTableContext ctx) {
TableId tableId = parseQualifiedTableId(ctx.tableName());
TableId tableId = parseQualifiedTableId(ctx.tableName().fullId());
tableEditor = databaseTables.editOrCreateTable(tableId);
super.enterColumnCreateTable(ctx);
}
@Override
public void exitColumnCreateTable(MySqlParser.ColumnCreateTableContext ctx) {
// Make sure that the table's character set has been set ...
if (!tableEditor.hasDefaultCharsetName()) {
tableEditor.setDefaultCharsetName(currentDatabaseCharset());
}
databaseTables.overwriteTable(tableEditor.create());
signalCreateTable(tableEditor.tableId(), ctx);
super.exitColumnCreateTable(ctx);
@ -404,8 +501,8 @@ public void exitColumnCreateTable(MySqlParser.ColumnCreateTableContext ctx) {
@Override
public void exitCopyCreateTable(MySqlParser.CopyCreateTableContext ctx) {
TableId tableId = parseQualifiedTableId(ctx.tableName(0));
TableId originalTableId = parseQualifiedTableId(ctx.tableName(1));
TableId tableId = parseQualifiedTableId(ctx.tableName(0).fullId());
TableId originalTableId = parseQualifiedTableId(ctx.tableName(1).fullId());
Table original = databaseTables.forTable(originalTableId);
if (original != null) {
databaseTables.overwriteTable(tableId, original.columns(), original.primaryKeyColumnNames(), original.defaultCharsetName());
@ -441,6 +538,13 @@ public void enterUniqueKeyTableConstraint(MySqlParser.UniqueKeyTableConstraintCo
}
super.enterUniqueKeyTableConstraint(ctx);
}
@Override
public void enterTableOptionCharset(MySqlParser.TableOptionCharsetContext ctx) {
String charsetName = withoutQuotes(ctx.charsetName());
tableEditor.setDefaultCharsetName(charsetName);
super.enterTableOptionCharset(ctx);
}
}
/**
@ -453,7 +557,7 @@ public void enterDropTable(MySqlParser.DropTableContext ctx) {
Interval interval = new Interval(ctx.start.getStartIndex(), ctx.tables().start.getStartIndex() - 1);
String prefix = ctx.start.getInputStream().getText(interval);
ctx.tables().tableName().forEach(tableNameContext -> {
TableId tableId = parseQualifiedTableId(tableNameContext);
TableId tableId = parseQualifiedTableId(tableNameContext.fullId());
databaseTables.removeTable(tableId);
signalDropTable(tableId, prefix + tableId.table()
+ (ctx.dropType != null ? " " + ctx.dropType.getText() : ""));
@ -474,7 +578,7 @@ private class AlterTableParserListener extends MySqlParserBaseListener {
@Override
public void enterAlterTable(MySqlParser.AlterTableContext ctx) {
TableId tableId = parseQualifiedTableId(ctx.tableName());
TableId tableId = parseQualifiedTableId(ctx.tableName().fullId());
tableEditor = databaseTables.editTable(tableId);
if (tableEditor == null) {
throw new ParsingException(null, "Trying to alter table " + getFullTableName(tableId)
@ -676,64 +780,6 @@ public void enterAlterByAddUniqueKey(MySqlParser.AlterByAddUniqueKeyContext ctx)
}
}
/**
* Parser listener for MySQL column definition queries.
*/
private class ColumnDefinitionParserListener extends MySqlParserBaseListener {
@Override
public void enterColumnDefinition(MySqlParser.ColumnDefinitionContext ctx) {
runIfAllEditorsNotNull(() -> {
resolveColumnDataType(ctx.dataType());
});
super.enterColumnDefinition(ctx);
}
@Override
public void enterUniqueKeyColumnConstraint(MySqlParser.UniqueKeyColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> {
if (!tableEditor.hasPrimaryKey()) {
// take the first unique constrain if no primary key is set
tableEditor.setPrimaryKeyNames(columnEditor.name());
}
});
super.enterUniqueKeyColumnConstraint(ctx);
}
@Override
public void enterPrimaryKeyColumnConstraint(MySqlParser.PrimaryKeyColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> {
// this rule will be parsed only if no primary key is set in a table
// otherwise the statement can't be executed due to multiple primary key error
columnEditor.optional(false);
tableEditor.setPrimaryKeyNames(columnEditor.name());
});
super.enterPrimaryKeyColumnConstraint(ctx);
}
@Override
public void enterNullNotnull(MySqlParser.NullNotnullContext ctx) {
runIfAllEditorsNotNull(() -> columnEditor.optional(ctx.NOT() == null));
super.enterNullNotnull(ctx);
}
@Override
public void enterDefaultColumnConstraint(MySqlParser.DefaultColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> columnEditor.generated(true));
super.enterDefaultColumnConstraint(ctx);
}
@Override
public void enterAutoIncrementColumnConstraint(MySqlParser.AutoIncrementColumnConstraintContext ctx) {
runIfAllEditorsNotNull(() -> {
columnEditor.autoIncremented(true);
columnEditor.generated(true);
});
super.enterAutoIncrementColumnConstraint(ctx);
}
}
/**
* Parser listener for MySQL rename table queries.
*/
@ -741,8 +787,8 @@ private class RenameTableParserListener extends MySqlParserBaseListener {
@Override
public void enterRenameTableClause(MySqlParser.RenameTableClauseContext ctx) {
TableId oldTable = parseQualifiedTableId(ctx.tableName(0));
TableId newTable = parseQualifiedTableId(ctx.tableName(1));
TableId oldTable = parseQualifiedTableId(ctx.tableName(0).fullId());
TableId newTable = parseQualifiedTableId(ctx.tableName(1).fullId());
databaseTables.renameTable(oldTable, newTable);
signalAlterTable(newTable, oldTable, ctx);
super.enterRenameTableClause(ctx);
@ -756,8 +802,10 @@ private class TruncateTableParserListener extends MySqlParserBaseListener {
@Override
public void enterTruncateTable(MySqlParser.TruncateTableContext ctx) {
TableId tableId = parseQualifiedTableId(ctx.tableName());
signalTruncateTable(tableId, ctx);
TableId tableId = parseQualifiedTableId(ctx.tableName().fullId());
// TODO rkuchar: uncomment. Tis is comment just because of test.
// The old parser is not signaling truncate events
// signalTruncateTable(tableId, ctx);
super.enterTruncateTable(ctx);
}
}
@ -770,7 +818,7 @@ private class CreateUniqueIndexParserListener extends MySqlParserBaseListener {
@Override
public void enterCreateIndex(MySqlParser.CreateIndexContext ctx) {
if (ctx.UNIQUE() != null) {
TableId tableId = parseQualifiedTableId(ctx.tableName());
TableId tableId = parseQualifiedTableId(ctx.tableName().fullId());
tableEditor = databaseTables.editTable(tableId);
if (tableEditor != null) {
if (!tableEditor.hasPrimaryKey()) {
@ -795,20 +843,42 @@ public void enterSetVariable(MySqlParser.SetVariableContext ctx) {
MySqlScope scope = null;
for (int i = 0; i < ctx.variableClause().size(); i++) {
MySqlParser.VariableClauseContext variableClauseContext = ctx.variableClause(i);
// default scope
String variableName;
if (variableClauseContext.uid() == null) {
// that mean that user variable is set, so do nothing with it
continue;
if (variableClauseContext.GLOBAL_ID() == null) {
// that mean that user variable is set, so do nothing with it
continue;
}
String variableIdentifier = variableClauseContext.GLOBAL_ID().getText();
if(variableIdentifier.startsWith("@@global.")) {
scope = MySqlScope.GLOBAL;
variableName = variableIdentifier.substring("@@global.".length());
}
else if (variableIdentifier.startsWith("@@session.")) {
scope = MySqlScope.SESSION;
variableName = variableIdentifier.substring("@@session.".length());
}
else if (variableIdentifier.startsWith("@@local.")) {
scope = MySqlScope.LOCAL;
variableName = variableIdentifier.substring("@@local.".length());
} else {
scope = MySqlScope.SESSION;
variableName = variableIdentifier.substring("@@".length());
}
}
else {
if (variableClauseContext.GLOBAL() != null) {
scope = MySqlScope.GLOBAL;
}
else if (variableClauseContext.SESSION() != null) {
scope = MySqlScope.SESSION;
}
else if (variableClauseContext.LOCAL() != null) {
scope = MySqlScope.LOCAL;
}
if (variableClauseContext.GLOBAL() != null) {
scope = MySqlScope.GLOBAL;
variableName = parseName(variableClauseContext.uid());
}
else if (variableClauseContext.SESSION() != null) {
scope = MySqlScope.SESSION;
}
String variableName = parseName(variableClauseContext.uid());
String value = withoutQuotes(ctx.expression(i));
systemVariables.setVariable(scope, variableName, value);
@ -876,6 +946,12 @@ public void enterUseStatement(MySqlParser.UseStatementContext ctx) {
*/
private class FinishSqlStatementParserListener extends MySqlParserBaseListener {
@Override
public void enterRoutineBody(MySqlParser.RoutineBodyContext ctx) {
throw new SkipException(ctx.getClass());
}
@Override
public void exitSqlStatement(MySqlParser.SqlStatementContext ctx) {
if (tableEditor != null) {