protected TableImpl(Table table) { this(table.id(), table.columns(), table.primaryKeyColumnNames(), table.defaultCharsetName()); }
private Column[] getColumnsForResultSet(Table table, ResultSet rs) throws SQLException { ResultSetMetaData metaData = rs.getMetaData(); Column[] columns = new Column[metaData.getColumnCount()]; for(int i = 0; i < columns.length; i++) { columns[i] = table.columnWithName(metaData.getColumnName(i + 1)); } return columns; }
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(); }
/** * Get the columns that are not included in the primary key for this table. * @return the list of columns that are not part of the primary key; never null but possibly empty */ default List<Column> nonPrimaryKeyColumns() { return filterColumns(col->!isPrimaryKeyColumn(col.name())); }
/** * Determine if the named column is part of the primary key. * * @param columnName the name of the column * @return {@code true} if a column exists in this table and it is part of the primary key, or {@code false} otherwise */ default boolean isPrimaryKeyColumn( String columnName ) { Column column = columnWithName(columnName); return column == null ? false : primaryKeyColumnNames().contains(column.name()); }
@Test public void shouldParseCreateTableStatementWithSignedTypes() { String ddl = "CREATE TABLE foo ( " + System.lineSeparator() + " c1 BIGINT SIGNED NOT NULL, " + System.lineSeparator() + " c2 INT UNSIGNED NOT NULL " + System.lineSeparator() + "); " + System.lineSeparator(); parser.parse(ddl, tables); assertThat(tables.size()).isEqualTo(1); Table foo = tables.forTable(new TableId(null, null, "foo")); assertThat(foo).isNotNull(); assertThat(foo.retrieveColumnNames()).containsExactly("c1", "c2"); assertThat(foo.primaryKeyColumnNames()).isEmpty(); assertColumn(foo, "c1", "BIGINT SIGNED", Types.BIGINT, -1, -1, false, false, false); assertColumn(foo, "c2", "INT UNSIGNED", Types.INTEGER, -1, -1, false, false, false); }
if (schemaPrefix == null) schemaPrefix = ""; final TableId tableId = table.id(); final String tableIdStr = tableSchemaName(tableId); final String schemaNamePrefix = schemaPrefix + tableIdStr; SchemaBuilder keySchemaBuilder = SchemaBuilder.struct().name(schemaNameAdjuster.adjust(schemaNamePrefix + ".Key")); AtomicBoolean hasPrimaryKey = new AtomicBoolean(false); table.columns().forEach(column -> { if (table.isPrimaryKeyColumn(column.name())) { Function<Object[], Object> keyGenerator = createKeyGenerator(keySchema, tableId, table.primaryKeyColumns()); Function<Object[], Struct> valueGenerator = createValueGenerator(valSchema, tableId, table.columns(), filter, mappers);
Table person = tables.forTable(DATABASE.getDatabaseName(), null, "person"); assertThat(person).isNotNull(); assertThat(person.filterColumns(col->col.isAutoIncremented())).isEmpty(); assertThat(person.primaryKeyColumnNames()).containsOnly("name"); assertThat(person.retrieveColumnNames()).containsExactly("name","birthdate","age","salary","bitStr"); assertThat(person.columnWithName("name").name()).isEqualTo("name"); assertThat(person.columnWithName("name").typeName()).isEqualTo("VARCHAR"); assertThat(person.columnWithName("name").jdbcType()).isEqualTo(Types.VARCHAR); assertThat(person.columnWithName("name").length()).isEqualTo(255); assertFalse(person.columnWithName("name").scale().isPresent()); assertThat(person.columnWithName("name").position()).isEqualTo(1); assertThat(person.columnWithName("name").isAutoIncremented()).isFalse(); assertThat(person.columnWithName("name").isGenerated()).isFalse(); assertThat(person.columnWithName("name").isOptional()).isFalse(); assertThat(person.columnWithName("birthdate").name()).isEqualTo("birthdate"); assertThat(person.columnWithName("birthdate").typeName()).isEqualTo("DATE"); assertThat(person.columnWithName("birthdate").jdbcType()).isEqualTo(Types.DATE); assertThat(person.columnWithName("birthdate").length()).isEqualTo(10); assertFalse(person.columnWithName("birthdate").scale().isPresent()); assertThat(person.columnWithName("birthdate").position()).isEqualTo(2); assertThat(person.columnWithName("birthdate").isAutoIncremented()).isFalse(); assertThat(person.columnWithName("birthdate").isGenerated()).isFalse(); assertThat(person.columnWithName("birthdate").isOptional()).isTrue(); assertThat(person.columnWithName("age").name()).isEqualTo("age"); assertThat(person.columnWithName("age").typeName()).isEqualTo("INT"); assertThat(person.columnWithName("age").jdbcType()).isEqualTo(Types.INTEGER); assertThat(person.columnWithName("age").length()).isEqualTo(10); assertThat(!person.columnWithName("age").scale().isPresent());
public TableChange(TableChangeType type, Table table) { this.type = type; this.table = table; this.id = table.id(); }
private Document toDocument(Table table) { Document document = Document.create(); document.set("defaultCharsetName", table.defaultCharsetName()); document.set("primaryKeyColumnNames", Array.create(table.primaryKeyColumnNames())); List<Document> columns = table.columns() .stream() .map(this::toDocument) .collect(Collectors.toList()); document.setArray("columns", Array.create(columns)); return document; }
/** * Utility to obtain a copy of a list of the columns that satisfy the specified predicate. * @param predicate the filter predicate; may not be null * @return the list of columns that satisfy the predicate; never null but possibly empty */ default List<Column> filterColumns( Predicate<Column> predicate ) { return columns().stream().filter(predicate).collect(Collectors.toList()); }
private boolean hasMissingUntoastedColumns(Table table, List<ReplicationMessage.Column> columns) { List<String> msgColumnNames = columns.stream() .map(ReplicationMessage.Column::getName) .collect(Collectors.toList()); // Compute list of table columns not present in the replication message List<String> missingColumnNames = table.columns() .stream() .filter(c -> !msgColumnNames.contains(c.name())) .map(Column::name) .collect(Collectors.toList()); List<String> toastableColumns = schema().getToastableColumnsForTableId(table.id()); logger.debug("msg columns: '{}' --- missing columns: '{}' --- toastableColumns: '{}", String.join(",", msgColumnNames), String.join(",", missingColumnNames), String.join(",", toastableColumns)); // Return `true` if we have some columns not in the replication message that are not toastable or that we do // not recognize return !toastableColumns.containsAll(missingColumnNames); }
@Test public void shouldCreateTableWhenEditorHasIdButNoColumns() { table = editor.tableId(id).create(); assertThat(table.columnWithName("any")).isNull(); assertThat(table.columns()).isEmpty(); assertThat(table.primaryKeyColumnNames()).isEmpty(); }
Column id = table.columnWithName("ID"); assertThat(id.isOptional()).isFalse(); assertThat(id.jdbcType()).isEqualTo(Types.NUMERIC); assertThat(id.typeName()).isEqualTo("NUMBER"); final Column name = table.columnWithName("NAME"); assertThat(name.isOptional()).isTrue(); assertThat(name.jdbcType()).isEqualTo(Types.VARCHAR); assertThat(name.length()).isEqualTo(1000); final Column score = table.columnWithName("SCORE"); assertThat(score.isOptional()).isTrue(); assertThat(score.jdbcType()).isEqualTo(Types.NUMERIC); assertThat(score.scale().get()).isEqualTo(2); assertThat(table.columns()).hasSize(4); assertThat(table.isPrimaryKeyColumn("ID"));
@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); }
@Test public void shouldParseCreateTableWithEnumAndSetColumns() { String ddl = "CREATE TABLE t ( c1 ENUM('a','b','c') NOT NULL, c2 SET('a','b','c') NULL);"; parser.parse(ddl, tables); assertThat(tables.size()).isEqualTo(1); Table t = tables.forTable(new TableId(null, null, "t")); assertThat(t).isNotNull(); assertThat(t.retrieveColumnNames()).containsExactly("c1", "c2"); assertThat(t.primaryKeyColumnNames()).isEmpty(); assertColumn(t, "c1", "ENUM", Types.CHAR, 1, -1, false, false, false); assertColumn(t, "c2", "SET", Types.CHAR, 5, -1, true, false, false); assertThat(t.columnWithName("c1").position()).isEqualTo(1); assertThat(t.columnWithName("c2").position()).isEqualTo(2); }
private TableEditor parseSelectElements(MySqlParser.SelectElementsContext ctx) { TableEditor table = Table.editor(); if (ctx.star != null) { tableByAlias.keySet().forEach(tableId -> { table.addColumns(tableByAlias.get(tableId).columns()); }); TableId tableId = parser.parseQualifiedTableId(((MySqlParser.SelectStarElementContext) selectElementContext).fullId()); Table selectedTable = tableByAlias.get(tableId); table.addColumns(selectedTable.columns());
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(); } }
@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); }