@Override public void enterAlterByDropPrimaryKey(MySqlParser.AlterByDropPrimaryKeyContext ctx) { parser.runIfNotNull(() -> { tableEditor.setPrimaryKeyNames(new ArrayList<>()); }, tableEditor); super.enterAlterByDropPrimaryKey(ctx); }
public Table getTableSchemaFromChangeTable(ChangeTable changeTable) throws SQLException { final DatabaseMetaData metadata = connection().getMetaData(); final TableId changeTableId = changeTable.getChangeTableId(); List<ColumnEditor> columnEditors = new ArrayList<>(); try (ResultSet rs = metadata.getColumns(realDatabaseName, changeTableId.schema(), changeTableId.table(), null)) { while (rs.next()) { readTableColumn(rs, changeTableId, null).ifPresent(columnEditors::add); } } // The first 5 columns and the last column of the change table are CDC metadata final List<Column> columns = columnEditors.subList(CHANGE_TABLE_DATA_COLUMN_OFFSET, columnEditors.size() - 1).stream() .map(c -> c.position(c.position() - CHANGE_TABLE_DATA_COLUMN_OFFSET).create()) .collect(Collectors.toList()); final List<String> pkColumnNames = new ArrayList<>(); prepareQuery(GET_LIST_OF_KEY_COLUMNS, ps -> ps.setInt(1, changeTable.getChangeTableObjectId()), rs -> { while (rs.next()) { pkColumnNames.add(rs.getString(2)); } }); Collections.sort(columns); return Table.editor() .tableId(changeTable.getSourceTableId()) .addColumns(columns) .setPrimaryKeyNames(pkColumnNames) .create(); }
@Override public TableEditor edit() { return new TableEditorImpl().tableId(id) .setColumns(columnDefs) .setPrimaryKeyNames(pkColumnNames) .setDefaultCharsetName(defaultCharsetName); } }
@Override public void enterUniqueKeyColumnConstraint(MySqlParser.UniqueKeyColumnConstraintContext ctx) { 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) { // 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); }
public Table getTableSchemaFromTable(ChangeTable changeTable) throws SQLException { final DatabaseMetaData metadata = connection().getMetaData(); List<Column> columns = new ArrayList<>(); try (ResultSet rs = metadata.getColumns( realDatabaseName, changeTable.getSourceTableId().schema(), changeTable.getSourceTableId().table(), null) ) { while (rs.next()) { readTableColumn(rs, changeTable.getSourceTableId(), null).ifPresent(ce -> columns.add(ce.create())); } } final List<String> pkColumnNames = readPrimaryKeyNames(metadata, changeTable.getSourceTableId()); Collections.sort(columns); return Table.editor() .tableId(changeTable.getSourceTableId()) .addColumns(columns) .setPrimaryKeyNames(pkColumnNames) .create(); }
.collect(Collectors.toList()); tableEditor.setPrimaryKeyNames(pkColumnNames);
protected Column parseCreateColumn(Marker start, TableEditor table, String columnName, String newColumnName) { // Obtain the column editor ... Column existingColumn = table.columnWithName(columnName); ColumnEditor column = existingColumn != null ? existingColumn.edit() : Column.editor().name(columnName); AtomicBoolean isPrimaryKey = new AtomicBoolean(false); parseColumnDefinition(start, columnName, tokens, table, column, isPrimaryKey); convertDefaultValueToSchemaType(column); // Update the table ... Column newColumnDefn = column.create(); table.addColumns(newColumnDefn); if (isPrimaryKey.get()) { table.setPrimaryKeyNames(newColumnDefn.name()); } if (newColumnName != null && !newColumnName.equalsIgnoreCase(columnName)) { table.renameColumn(columnName, newColumnName); columnName = newColumnName; } // ALTER TABLE allows reordering the columns after the definition ... if (tokens.canConsume("FIRST")) { table.reorderColumn(columnName, null); } else if (tokens.canConsume("AFTER")) { table.reorderColumn(columnName, tokens.consume()); } return table.columnWithName(newColumnDefn.name()); }
private Table tableFromFromMessage(List<ReplicationMessage.Column> columns, Table table) { return table.edit() .setColumns(columns.stream() .map(column -> { final PostgresType type = column.getType(); final ColumnEditor columnEditor = Column.editor() .name(column.getName()) .jdbcType(type.getJdbcId()) .type(type.getName()) .optional(column.isOptional()) .nativeType(type.getOid()); columnEditor.length(column.getTypeMetadata().getLength()); columnEditor.scale(column.getTypeMetadata().getScale()); return columnEditor.create(); }) .collect(Collectors.toList()) ) .setPrimaryKeyNames(table.filterColumnNames(c -> table.isPrimaryKeyColumn(c.name()))).create(); } }
protected void parseCreateIndex(Marker start) { boolean unique = tokens.canConsume("UNIQUE"); tokens.canConsumeAnyOf("FULLTEXT", "SPATIAL"); tokens.consume("INDEX"); String indexName = tokens.consume(); // index name if (tokens.matches("USING")) { parseIndexType(start); } TableId tableId = null; if (tokens.canConsume("ON")) { // Usually this is required, but in some cases ON is not required tableId = parseQualifiedTableName(start); } if (unique && tableId != null) { // This is a unique index, and we can mark the index's columns as the primary key iff there is not already // a primary key on the table. (Should a PK be created later via an alter, then it will overwrite this.) TableEditor table = databaseTables.editTable(tableId); if (table != null && !table.hasPrimaryKey()) { List<String> names = parseIndexColumnNames(start); if (table.columns().stream().allMatch(Column::isRequired)) { databaseTables.overwriteTable(table.setPrimaryKeyNames(names).create()); } } } // We don't care about any other statements or the rest of this statement ... consumeRemainingStatement(start); // TODO fix: signal should be send only when some changes on table are made signalCreateIndex(indexName, tableId, start); debugParsed(start); }
protected void parseTableElement(Marker start, TableEditor table) { if (tokens.matchesAnyOf("CONSTRAINT", "UNIQUE", "PRIMARY", "FOREIGN", "CHECK")) { parseTableConstraintDefinition(start, table); } else if (tokens.matches("LIKE")) { parseTableLikeClause(start, table); } else if (tokens.matches("REF", "IS")) { parseSelfReferencingColumnSpec(start, table); } else { // Obtain the column editor ... String columnName = tokens.consume(); Column existingColumn = table.columnWithName(columnName); ColumnEditor column = existingColumn != null ? existingColumn.edit() : Column.editor().name(columnName); AtomicBoolean isPrimaryKey = new AtomicBoolean(false); if (tokens.matches("WITH", "OPTIONS")) { parseColumnOptions(start, columnName, tokens, column); } else { parseColumnDefinition(start, columnName, tokens, table, column, isPrimaryKey); } // Update the table ... Column newColumnDefn = column.create(); table.addColumns(newColumnDefn); if (isPrimaryKey.get()) { table.setPrimaryKeyNames(newColumnDefn.name()); } } }
protected void parseTableConstraintDefinition(Marker start, TableEditor table) { if (tokens.canConsume("CONSTRAINT")) { parseSchemaQualifiedName(start); // constraint name } if (tokens.canConsume("UNIQUE", "(", "VALUE", ")")) { table.setUniqueValues(); } else if (tokens.canConsume("UNIQUE") || tokens.canConsume("PRIMARY", "KEY")) { List<String> pkColumnNames = parseColumnNameList(start); table.setPrimaryKeyNames(pkColumnNames); } else if (tokens.canConsume("FOREIGN", "KEY")) { parseColumnNameList(start); tokens.consume("REFERENCES"); parseSchemaQualifiedName(start); if (tokens.canConsume('(')) { parseColumnNameList(start); } if (tokens.canConsume("MATCH")) { tokens.consumeAnyOf("FULL", "PARTIAL", "SIMPLE"); if (tokens.canConsume("ON")) { parseReferentialTriggeredActions(start); } } } else if (tokens.canConsume("CHECK", "(")) { // Consume everything (we don't care what it is) ... tokens.consumeThrough(')', '('); } }
table.addColumn(newColumnDefn); if (isPrimaryKey.get()) { table.setPrimaryKeyNames(newColumnDefn.name());
@Test(expected = IllegalArgumentException.class) public void shouldNotAllowAddingPrimaryKeyColumnWhenNotFound() { editor.tableId(id); Column c1 = columnEditor.name("C1").type("VARCHAR").jdbcType(Types.VARCHAR).length(10).position(1).create(); Column c2 = columnEditor.name("C2").type("NUMBER").jdbcType(Types.NUMERIC).length(5).position(1).create(); Column c3 = columnEditor.name("C3").type("DATE").jdbcType(Types.DATE).position(1).create(); editor.addColumns(c1, c2, c3); editor.setPrimaryKeyNames("C1", "WOOPS"); }
@Test public void shouldFindGeneratedColumns() { editor.tableId(id); Column c1 = columnEditor.name("C1").type("VARCHAR").jdbcType(Types.VARCHAR).length(10).position(1).create(); Column c2 = columnEditor.name("C2").type("NUMBER").jdbcType(Types.NUMERIC).length(5).generated(true).create(); Column c3 = columnEditor.name("C3").type("DATE").jdbcType(Types.DATE).generated(true).create(); editor.addColumns(c1, c2, c3); editor.setPrimaryKeyNames("C1"); table = editor.create(); assertThat(table.retrieveColumnNames()).containsExactly("C1", "C2", "C3"); table.columns().forEach(col -> { assertThat(table.isGenerated(col.name())).isEqualTo(col.isGenerated()); }); assertValidPositions(editor); }
@Test public void shouldFindAutoIncrementedColumns() { editor.tableId(id); Column c1 = columnEditor.name("C1").type("VARCHAR").jdbcType(Types.VARCHAR).length(10).position(1).create(); Column c2 = columnEditor.name("C2").type("NUMBER").jdbcType(Types.NUMERIC).length(5).autoIncremented(true).create(); Column c3 = columnEditor.name("C3").type("DATE").jdbcType(Types.DATE).autoIncremented(true).create(); editor.addColumns(c1, c2, c3); editor.setPrimaryKeyNames("C1"); table = editor.create(); assertThat(table.retrieveColumnNames()).containsExactly("C1", "C2", "C3"); table.columns().forEach(col -> { assertThat(table.isAutoIncremented(col.name())).isEqualTo(col.isAutoIncremented()); }); assertValidPositions(editor); }
@Before public void beforeEach() { table = Table.editor() .tableId(id) .addColumns(Column.editor().name("C1") .type("VARCHAR").jdbcType(Types.VARCHAR).length(10) .generated(true) .optional(false) .create(), Column.editor().name("C2") .type("NUMBER").jdbcType(Types.NUMERIC).length(5) .optional(false) .create(), Column.editor().name("C3") .type("DATE").jdbcType(Types.DATE).length(4) .optional(true) .create(), Column.editor().name("C4") .type("COUNTER").jdbcType(Types.INTEGER) .autoIncremented(true) .optional(true) .create()) .setPrimaryKeyNames("C1", "C2") .create(); c1 = table.columnWithName("C1"); c2 = table.columnWithName("C2"); c3 = table.columnWithName("C3"); c4 = table.columnWithName("C4"); }
@Test public void shouldAllowAddingPrimaryKeyColumnWhenFound() { editor.tableId(id); Column c1 = columnEditor.name("C1").type("VARCHAR").jdbcType(Types.VARCHAR).length(10).position(1).create(); Column c2 = columnEditor.name("C2").type("NUMBER").jdbcType(Types.NUMERIC).length(5).position(1).create(); Column c3 = columnEditor.name("C3").type("DATE").jdbcType(Types.DATE).position(1).create(); editor.addColumns(c1, c2, c3); editor.setPrimaryKeyNames("C1"); c1 = editor.columnWithName(c1.name()); c2 = editor.columnWithName(c2.name()); c3 = editor.columnWithName(c3.name()); assertThat(c1.position()).isEqualTo(1); assertThat(c2.position()).isEqualTo(2); assertThat(c3.position()).isEqualTo(3); table = editor.create(); assertThat(table.retrieveColumnNames()).containsExactly("C1", "C2", "C3"); assertThat(table.columns()).containsExactly(c1, c2, c3); assertThat(table.primaryKeyColumnNames()).containsOnly("C1"); assertValidPositions(editor); }
.optional(false) .create()) .setPrimaryKeyNames("first") .create();
@Test public void shouldBuildTableSchemaFromTableWithoutPrimaryKey() { table = table.edit().setPrimaryKeyNames().create(); schema = new TableSchemaBuilder(new JdbcValueConverters(), adjuster, SchemaBuilder.struct().build()) .create(prefix, "sometopic", table, null, null);