diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java index 9713baf0e9552deeac0b936327cf14d9dd946baa..cfec5759c5575de45c8ff5c387862a3a06a2a048 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java @@ -405,10 +405,16 @@ public interface MariaDbMapper { stringBuilder.append("`") .append(nameToInternalName("database_id")) - .append("` VARCHAR(255) NOT NULL, "); - stringBuilder.append("`") - .append(nameToInternalName("record_id")) - .append("` VARCHAR(255) NOT NULL, "); + .append("` VARCHAR(128) NOT NULL, "); + + // Add each primary key column defined in the DTO with reduced length + for (String pk : data.getConstraints().getPrimaryKey()) { + stringBuilder.append("`") + .append(nameToInternalName(pk)) + .append("` VARCHAR(128) NOT NULL, "); + } + + // Add the timestamp columns (TIMESTAMP remains unchanged) stringBuilder.append("`") .append(nameToInternalName("timestamp_add")) .append("` TIMESTAMP NOT NULL, "); @@ -416,13 +422,20 @@ public interface MariaDbMapper { .append(nameToInternalName("timestamp_delete")) .append("` TIMESTAMP NOT NULL"); - stringBuilder.append(", PRIMARY KEY (") - .append("`").append(nameToInternalName("database_id")).append("`, ") - .append("`").append(nameToInternalName("record_id")).append("`, ") - .append("`").append(nameToInternalName("timestamp_add")).append("`, ") - .append("`").append(nameToInternalName("timestamp_delete")).append("`") - .append(")"); + // Build the PRIMARY KEY clause including all columns above + stringBuilder.append(", PRIMARY KEY ("); + // Include the database_id column + stringBuilder.append("`").append(nameToInternalName("database_id")).append("`"); + // Include each primary key column from the DTO + for (String pk : data.getConstraints().getPrimaryKey()) { + stringBuilder.append(", `").append(nameToInternalName(pk)).append("`"); + } + // Include the timestamp columns + stringBuilder.append(", `").append(nameToInternalName("timestamp_add")).append("`"); + stringBuilder.append(", `").append(nameToInternalName("timestamp_delete")).append("`"); + stringBuilder.append(")"); + // Finish the query with system versioning stringBuilder.append(") WITH SYSTEM VERSIONING") .append(";"); log.trace("mapped create timestamp table statement: {}", stringBuilder); @@ -430,6 +443,8 @@ public interface MariaDbMapper { } + + /** * Selects the row count from a table/view. * @@ -647,6 +662,54 @@ public interface MariaDbMapper { return statement.toString(); } + default String tupleToRawCreateTimestampQuery(TableDto table, TupleDto data, Timestamp tsAdd, Timestamp tsDelete) + throws TableMalformedException { + if (table.getColumns().isEmpty()) { + throw new TableMalformedException("Columns are not known"); + } + + final StringBuilder statement = new StringBuilder("INSERT INTO `") + .append(table.getDatabase().getInternalName()) + .append("`.`") + .append(table.getInternalName()).append("_timestamps") + .append("` ("); + + + statement.append("`").append(nameToInternalName("database_id")).append("`"); + + for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) { + String pkColumn = pk.getColumn().getInternalName(); + // Optionally verify that data contains the primary key value: + if (!data.getData().containsKey(pkColumn)) { + log.error("Primary key column {} not found in tuple data", pkColumn); + throw new IllegalArgumentException("Missing primary key column data: " + pkColumn); + } + statement.append(", `").append(pkColumn).append("`"); + } + + statement.append(", `").append(nameToInternalName("timestamp_add")).append("`") + .append(", `").append(nameToInternalName("timestamp_delete")).append("`"); + + statement.append(") VALUES ("); + + + statement.append("?"); + + for (int i = 0; i < table.getConstraints().getPrimaryKey().size(); i++) { + statement.append(", ?"); + } + + // - Then the two placeholders for the timestamp columns + statement.append(", ?"); // for tsAdd + statement.append(", ?"); // for tsDelete + + statement.append(");"); + + log.trace("Mapped create tuple timestamp query: {}", statement.toString()); + return statement.toString(); + } + + default String tupleToRawSelectSystemTimestampsQuery(TableDto table, TupleDto data) throws TableMalformedException { if (table.getConstraints() == null || table.getConstraints().getPrimaryKey() == null || diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java index ecc8ac78609153aedb3cadfe99979d763019126b..7b0f7a4668c974ec0b71e037e29fe365568fe1a7 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java @@ -24,10 +24,7 @@ import org.springframework.stereotype.Service; import java.sql.*; import java.time.Instant; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; +import java.util.*; @Log4j2 @Service @@ -307,8 +304,7 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi statement.executeUpdate(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); - log.info(table.toString()); - log.info(data.toString()); + // Now, fetch the system timestamps using the primary key values. String selectQuery = mariaDbMapper.tupleToRawSelectSystemTimestampsQuery(table, data); @@ -316,18 +312,46 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi ResultSet rs = selectStmt.executeQuery(); if (rs.next()) { - // Build a log message with primary key columns and the two timestamps. - StringBuilder rowInfo = new StringBuilder(); + // Extract primary key values and build a map for TupleDto + Map<String, Object> pkData = new HashMap<>(); for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) { String pkColumn = pk.getColumn().getInternalName(); Object value = rs.getObject(pkColumn); - rowInfo.append(pkColumn).append("=").append(value).append(" "); + pkData.put(pkColumn, value); } Timestamp tsAdd = rs.getTimestamp("ROW_START"); Timestamp tsDelete = rs.getTimestamp("ROW_END"); - rowInfo.append("timestampAdd=").append(tsAdd).append(" "); - rowInfo.append("timestampDelete=").append(tsDelete); - log.info("Fetched system timestamps for tuple: {}", rowInfo.toString().trim()); + + TupleDto tupleData = new TupleDto(pkData); + + // Generate the insert query for the timestamp table. + String insertQuery = mariaDbMapper.tupleToRawCreateTimestampQuery(table, tupleData, tsAdd, tsDelete); + log.debug("Generated insert query for timestamp table: {}", insertQuery); + + // Execute the query using a prepared statement. + try (PreparedStatement ps = connection.prepareStatement(insertQuery)) { + int parameterIndex = 1; + + // Bind the database_id value. Adjust the value as appropriate. + // For example, you might have a method like table.getDatabase().getId() or another source. + String databaseId = table.getDatabase().getInternalName(); // or another appropriate field + ps.setString(parameterIndex++, databaseId); + + // Bind each primary key value, in the order they are defined. + for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) { + String pkColumn = pk.getColumn().getInternalName(); + ps.setObject(parameterIndex++, pkData.get(pkColumn)); + } + + ps.setTimestamp(parameterIndex++, tsAdd); + ps.setTimestamp(parameterIndex++, tsDelete); + + int rowsInserted = ps.executeUpdate(); + log.info("Inserted {} row(s) into timestamp table.", rowsInserted); + } catch (SQLException e) { + log.error("Error inserting into timestamp table", e); + throw new RuntimeException("Error inserting into timestamp table", e); + } } else { log.warn("No tuple found for the given primary key values"); }