package com.zendesk.maxwell.replication;
import com.google.code.or.binlog.impl.event.UpdateRowsEventV2;
import com.google.code.or.common.glossary.Pair;
import com.google.code.or.common.glossary.Row;
import com.google.code.or.common.glossary.column.BitColumn;
import com.zendesk.maxwell.MaxwellFilter;
import com.zendesk.maxwell.row.RowMap;
import com.zendesk.maxwell.schema.ColumnWithDefinition;
import com.zendesk.maxwell.schema.ColumnWithDefinitionList;
import com.zendesk.maxwell.schema.Table;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class UpdateRowsEvent extends AbstractRowsEvent {
private final com.google.code.or.binlog.impl.event.UpdateRowsEvent event;
public UpdateRowsEvent(com.google.code.or.binlog.impl.event.UpdateRowsEvent e, Table t, MaxwellFilter f, long lastHeartbeat) {
super(e, t, f, lastHeartbeat);
this.event = e;
}
public UpdateRowsEvent(UpdateRowsEventV2 e2, Table table, MaxwellFilter filter, long lastHeartbeat) {
super(e2, table, filter, lastHeartbeat);
com.google.code.or.binlog.impl.event.UpdateRowsEvent e = new com.google.code.or.binlog.impl.event.UpdateRowsEvent(e2.getHeader());
e.setBinlogFilename(e2.getBinlogFilename());
e.setColumnCount(e2.getColumnCount());
e.setRows(e2.getRows());
e.setTableId(e2.getTableId());
e.setUsedColumnsAfter(e2.getUsedColumnsAfter());
e.setUsedColumnsBefore(e2.getUsedColumnsBefore());
e.setReserved(e2.getReserved());
this.event = e;
}
@Override
public List<Row> getRows() { // only for filterRows() at the moment. need to refactor that.
ArrayList<Row> result = new ArrayList<Row>();
for (Pair<Row> p : event.getRows()) {
result.add(p.getAfter());
}
return result;
}
@Override
public String sqlOperationString() {
return "REPLACE INTO ";
}
@Override
public String getType() {
return "update";
}
@Override
public List<RowMap> jsonMaps() {
ArrayList<RowMap> list = new ArrayList<>();
for (Pair<Row> p : event.getRows() ) {
Row after = p.getAfter();
Row before = p.getBefore();
RowMap rowMap = buildRowMap();
for ( ColumnWithDefinition cd : new ColumnWithDefinitionList(table, after, event.getUsedColumnsAfter())) {
rowMap.putData(cd.definition.getName(), cd.asJSON());
}
for ( ColumnWithDefinition cd : new ColumnWithDefinitionList(table, before, event.getUsedColumnsBefore())) {
String name = cd.definition.getName();
Object beforeValue = cd.asJSON();
if (!rowMap.hasData(name)) {
/*
If we find a column in the BEFORE image that's *not* present in the AFTER image,
we're running in binlog_row_image = MINIMAL. In this case, the BEFORE image acts
as a sort of WHERE clause to update rows with the new values (present in the AFTER image).
In order to reconstruct as much of the row as posssible, here we fill in
missing data in the rowMap with values from the BEFORE image
*/
rowMap.putData(name, beforeValue);
} else {
if (!Objects.equals(rowMap.getData(name), beforeValue)) {
rowMap.putOldData(name, beforeValue);
}
}
}
list.add(rowMap);
}
return list;
}
@Override
protected BitColumn getUsedColumns() {
return event.getUsedColumnsAfter(); // not actually used, since we override jsonMaps()
}
}