Skip to content
Snippets Groups Projects
Commit eaef815e authored by maxlastglance's avatar maxlastglance
Browse files

update timestamp table on update

parent 891eef61
No related branches found
No related tags found
No related merge requests found
......@@ -618,6 +618,42 @@ public interface MariaDbMapper {
return statement.toString();
}
default String tupleToRawUpdateTimestampQuery(TableDto table, TupleUpdateDto data, Timestamp tsAdd, Timestamp tsDelete)
throws TableMalformedException {
if (table.getColumns().isEmpty()) {
throw new TableMalformedException("Columns are not known");
}
final StringBuilder statement = new StringBuilder("UPDATE `")
.append(table.getDatabase().getInternalName())
.append("`.`")
.append(table.getInternalName()).append("_timestamps")
.append("` SET ");
// Set the two timestamp columns
statement.append("`").append(nameToInternalName("timestamp_add")).append("` = ?, ");
statement.append("`").append(nameToInternalName("timestamp_delete")).append("` = ? ");
// Set each primary key to its new value
for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
String pkColumn = pk.getColumn().getInternalName();
statement.append(", `").append(pkColumn).append("` = ? ");
}
// WHERE clause: match on database_id and the old primary key values
statement.append("WHERE ");
statement.append("`").append(nameToInternalName("database_id")).append("` = ? ");
for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
String pkColumn = pk.getColumn().getInternalName();
statement.append("AND `").append(pkColumn).append("` = ? ");
}
statement.append(";");
log.trace("Mapped update query for timestamp table: {}", statement.toString());
return statement.toString();
}
default String tupleToRawCreateQuery(TableDto table, TupleDto data) throws TableMalformedException {
if (table.getColumns().isEmpty()) {
throw new TableMalformedException("Columns are not known");
......
......@@ -25,6 +25,7 @@ import org.springframework.stereotype.Service;
import java.sql.*;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
@Log4j2
@Service
......@@ -368,31 +369,99 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi
}
@Override
public void updateTuple(TableDto table, TupleUpdateDto data) throws SQLException,
QueryMalformedException, TableMalformedException {
public void updateTuple(TableDto table, TupleUpdateDto data)
throws SQLException, QueryMalformedException, TableMalformedException {
log.trace("update tuple: {}", data);
/* prepare the statement */
final ComboPooledDataSource dataSource = getDataSource(table);
final Connection connection = dataSource.getConnection();
try {
// Build and execute the main update query for the tuple.
final int[] idx = new int[]{1};
final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.tupleToRawUpdateQuery(table, data));
/* set data */
final PreparedStatement statement = connection.prepareStatement(
mariaDbMapper.tupleToRawUpdateQuery(table, data));
// Bind new values (data to be updated; may include new primary key values)
for (Map.Entry<String, Object> entry : data.getData().entrySet()) {
mariaDbMapper.prepareStatementWithColumnTypeObject(statement,
getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue());
getColumnType(table.getColumns(), entry.getKey()),
idx[0], entry.getKey(), entry.getValue());
idx[0]++;
}
/* set key(s) */
// Bind old primary key values (for the WHERE clause)
for (Map.Entry<String, Object> entry : data.getKeys().entrySet()) {
mariaDbMapper.prepareStatementWithColumnTypeObject(statement,
getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue());
getColumnType(table.getColumns(), entry.getKey()),
idx[0], entry.getKey(), entry.getValue());
idx[0]++;
}
final long start = System.currentTimeMillis();
long start = System.currentTimeMillis();
statement.executeUpdate();
log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
log.trace("Main update executed in {} ms", System.currentTimeMillis() - start);
connection.commit();
// After the main update, select the system timestamps.
String selectQuery = mariaDbMapper.tupleToRawSelectSystemTimestampsQuery(
table, TupleDto.builder().data(data.getData()).build());
try (PreparedStatement selectStmt = connection.prepareStatement(selectQuery);
ResultSet rs = selectStmt.executeQuery()) {
if (rs.next()) {
// Retrieve the new primary key values from the updated row (if needed).
Map<String, Object> pkData = new HashMap<>();
for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
pkData.put(pk.getColumn().getInternalName(),
rs.getObject(pk.getColumn().getInternalName()));
}
Timestamp tsAdd = rs.getTimestamp("ROW_START");
Timestamp tsDelete = rs.getTimestamp("ROW_END");
// Build the update query for the _timestamps table.
String updateTsQuery = mariaDbMapper.tupleToRawUpdateTimestampQuery(
table, data, tsAdd, tsDelete);
try (PreparedStatement ps = connection.prepareStatement(updateTsQuery)) {
int parameterIndex = 1;
// SET clause: new timestamp values.
ps.setTimestamp(parameterIndex++, tsAdd);
ps.setTimestamp(parameterIndex++, tsDelete);
// SET clause: new primary key values (assumed to be provided in data.getData())
for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
log.info("Setting new primary key value: {}", pk.getColumn().getInternalName());
Object newPkValue = data.getData().get(pk.getColumn().getInternalName());
log.info("New primary key value: {}", newPkValue);
ps.setObject(parameterIndex++, newPkValue);
}
// WHERE clause: bind the database id.
String databaseId = table.getDatabase().getInternalName();
ps.setString(parameterIndex++, databaseId);
// WHERE clause: bind the old primary key values.
for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
log.info("Setting new primary key value: {}", pk.getColumn().getInternalName());
Object oldPkValue = data.getKeys().get(pk.getColumn().getInternalName());
log.info("Old primary key value: {}", oldPkValue);
ps.setObject(parameterIndex++, oldPkValue);
}
log.info("SQL Query: " + updateTsQuery);
log.info("Bound parameters: tsAdd={}, tsDelete={}, newPKValues={}, databaseId={}, oldPKValues={}",
tsAdd, tsDelete,
table.getConstraints().getPrimaryKey().stream()
.map(pk -> data.getData().get(pk.getColumn().getInternalName()))
.collect(Collectors.toList()),
databaseId,
table.getConstraints().getPrimaryKey().stream()
.map(pk -> data.getKeys().get(pk.getColumn().getInternalName()))
.collect(Collectors.toList()));
int rowsUpdated = ps.executeUpdate();
log.info("Updated {} row(s) in {}_timestamps table.", rowsUpdated, table.getInternalName());
}
} else {
log.warn("No row found for updated PK; timestamps not updated.");
}
}
} catch (SQLException e) {
connection.rollback();
log.error("Failed to update tuple: {}", e.getMessage());
......@@ -403,6 +472,7 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi
log.info("Updated tuple(s) from table: {}.{}", table.getDatabase(), table.getInternalName());
}
public ColumnTypeDto getColumnType(List<ColumnDto> columns, String name) throws QueryMalformedException {
final Optional<ColumnDto> optional = columns.stream()
.filter(c -> c.getInternalName().equals(name)).findFirst();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment