RowHandler handler) {
LOG.debug("Running online plan: {}", plan);
Map<RowType,HKeyChecker> checkers = new HashMap<>();
QueryBindings bindings = context.createBindings();
Cursor cursor = API.cursor(plan, context, bindings);
Rebindable rebindable = getRebindable(cursor);
cursor.openTopLevel();
try {
boolean done = false;
Row lastCommitted = null;
boolean checkOnlineError = true;
long rowCount = 0;
while(!done) {
Row row = cursor.next();
boolean didCommit = false;
boolean didRollback = false;
if(checkOnlineError) {
// Checked once per transaction here and in final phase in DDLFunctions
checkOnlineError(session, schemaManager);
checkOnlineError = false;
}
if(row != null) {
rowCount++;
RowType rowType = row.rowType();
// No way to pre-populate this map as Operator#rowType() is optional and insufficient.
HKeyChecker checker = checkers.get(rowType);
if(checker == null) {
if(rowType.hasTable()) {
checker = new SchemaManagerChecker(rowType.table().getTableId());
} else {
checker = new FalseChecker();
}
checkers.put(row.rowType(), checker);
}
try {
if(handler != null) {
//TODO: Not correct but only option for createAs due to hidden PK
Key hKey = new Key (null, 2047);
row.hKey().copyTo(hKey);
if (!checker.contains(schemaManager, session, hKey)) {
handler.handleRow(row);
} else {
LOG.trace("skipped row: {}", row);
}
}
didCommit = txnService.periodicallyCommit(session);
} catch(InvalidOperationException e) {
if(!e.getCode().isRollbackClass()) {
throw e;
}
didRollback = true;
}
} else {
// Cursor exhausted, completely finished
didRollback = txnService.commitOrRetryTransaction(session);
done = didCommit = !didRollback;
if(didCommit) {
txnService.beginTransaction(session);
}
}
if(didCommit) {
LOG.debug("Committed up to row: {}: {} rows", row, rowCount);
checkOnlineError = true;
lastCommitted = row;
checkers.clear();
} else if(didRollback) {
LOG.debug("Rolling back to row: {}", lastCommitted);
checkOnlineError = true;
checkers.clear();
txnService.rollbackTransactionIfOpen(session);
txnService.beginTransaction(session);
cursor.closeTopLevel();
rebindable.rebind((lastCommitted == null) ? null : lastCommitted.hKey(), true);
cursor.openTopLevel();
}
}
} finally {
cursor.closeTopLevel();