package org.tmatesoft.svn.core.internal.wc17.db;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.SqlJetTransactionMode;
import org.tmatesoft.sqljet.core.table.ISqlJetCursor;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.internal.db.*;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNEventFactory;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext;
import org.tmatesoft.svn.core.internal.wc17.SVNWCUtils;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbKind;
import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb.DirParsedInfo;
import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbCreateSchema;
import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema;
import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema.NODES__Fields;
import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema.REVERT_LIST__Fields;
import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbStatements;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNEventAction;
import org.tmatesoft.svn.util.SVNLogType;
import java.io.File;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.*;
public class SvnWcDbRevert extends SvnWcDbShared {
public static void revert(SVNWCDbRoot root, File localRelPath) throws SVNException {
SVNSqlJetDb sdb = root.getSDb();
SvnRevertNodesTrigger nodesTableTrigger = new SvnRevertNodesTrigger(sdb);
SvnRevertActualNodesTrigger actualNodesTableTrigger = new SvnRevertActualNodesTrigger(sdb);
SVNSqlJetStatement stmt = sdb.getStatement(SVNWCDbStatements.SELECT_NODE_INFO);
long opDepth;
try {
stmt.bindf("is", root.getWcId(), localRelPath);
if (!stmt.next()) {
reset(stmt);
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_ACTUAL_NODE);
long affectedRows;
try {
((SVNSqlJetTableStatement) stmt).addTrigger(actualNodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
affectedRows = stmt.done();
} finally {
stmt.reset();
}
if (affectedRows > 0) {
stmt = sdb.getStatement(SVNWCDbStatements.SELECT_ACTUAL_CHILDREN_INFO);
try {
stmt.bindf("is", root.getWcId(), localRelPath);
if (stmt.next()) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_INVALID_OPERATION_DEPTH, "Can''t revert ''{0}'' without reverting children", root.getAbsPath(localRelPath));
SVNErrorManager.error(err, SVNLogType.WC);
}
} finally {
reset(stmt);
}
return;
}
nodeNotFound(root, localRelPath);
}
opDepth = getColumnInt64(stmt, NODES__Fields.op_depth);
} finally {
reset(stmt);
}
if (opDepth > 0 && opDepth == SVNWCUtils.relpathDepth(localRelPath)) {
boolean haveRow;
stmt = sdb.getStatement(SVNWCDbStatements.SELECT_GE_OP_DEPTH_CHILDREN);
try {
stmt.bindf("isi", root.getWcId(), localRelPath, opDepth);
haveRow = stmt.next();
} finally {
reset(stmt);
}
if (haveRow) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_INVALID_OPERATION_DEPTH, "Can''t revert ''{0}'' without reverting children", root.getAbsPath(localRelPath));
SVNErrorManager.error(err, SVNLogType.WC);
}
stmt = sdb.getStatement(SVNWCDbStatements.SELECT_ACTUAL_CHILDREN_INFO);
try {
stmt.bindf("is", root.getWcId(), localRelPath);
haveRow = stmt.next();
} finally {
reset(stmt);
}
if (haveRow) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_INVALID_OPERATION_DEPTH, "Can''t revert ''{0}'' without reverting children", root.getAbsPath(localRelPath));
SVNErrorManager.error(err, SVNLogType.WC);
}
stmt = sdb.getStatement(SVNWCDbStatements.UPDATE_OP_DEPTH_INCREASE_RECURSIVE);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(nodesTableTrigger);
stmt.bindf("isi", root.getWcId(), localRelPath, opDepth);
stmt.done();
} finally {
stmt.reset();
}
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_WORKING_NODE);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(nodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
stmt.done();
} finally {
stmt.reset();
}
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_WC_LOCK_ORPHAN);
try {
stmt.bindf("is", root.getWcId(), localRelPath);
stmt.done();
} finally {
stmt.reset();
}
}
long affectedRows;
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_ACTUAL_NODE_LEAVING_CHANGELIST);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(actualNodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
affectedRows = stmt.done();
} finally {
stmt.reset();
}
if (affectedRows == 0) {
stmt = sdb.getStatement(SVNWCDbStatements.CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(actualNodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
stmt.done();
} finally {
stmt.reset();
}
}
}
public static void revertRecursive(SVNWCDbRoot root, File localRelPath) throws SVNException {
SVNSqlJetDb sdb = root.getSDb();
SvnRevertNodesTrigger nodesTableTrigger = new SvnRevertNodesTrigger(sdb);
SvnRevertActualNodesTrigger actualNodesTableTrigger = new SvnRevertActualNodesTrigger(sdb);
SVNSqlJetStatement stmt = sdb.getStatement(SVNWCDbStatements.SELECT_NODE_INFO);
long opDepth;
try {
stmt.bindf("is", root.getWcId(), localRelPath);
if (!stmt.next()) {
reset(stmt);
long affectedRows;
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_ACTUAL_NODE_RECURSIVE);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(actualNodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
affectedRows = stmt.done();
} finally {
stmt.reset();
}
if (affectedRows > 0) {
return;
}
nodeNotFound(root, localRelPath);
}
opDepth = getColumnInt64(stmt, NODES__Fields.op_depth);
} finally {
reset(stmt);
}
if (opDepth > 0 && opDepth != SVNWCUtils.relpathDepth(localRelPath)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_INVALID_OPERATION_DEPTH, "Can''t revert ''{0}'' without reverting parent", root.getAbsPath(localRelPath));
SVNErrorManager.error(err, SVNLogType.WC);
}
if (opDepth == 0) {
opDepth = 1;
}
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_NODES_RECURSIVE);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(nodesTableTrigger);
stmt.bindf("isi", root.getWcId(), localRelPath, opDepth);
stmt.done();
} finally {
stmt.reset();
}
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(actualNodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
stmt.done();
} finally {
stmt.reset();
}
stmt = sdb.getStatement(SVNWCDbStatements.CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE);
try {
((SVNSqlJetTableStatement) stmt).addTrigger(actualNodesTableTrigger);
stmt.bindf("is", root.getWcId(), localRelPath);
stmt.done();
} finally {
stmt.reset();
}
stmt = sdb.getStatement(SVNWCDbStatements.DELETE_WC_LOCK_ORPHAN_RECURSIVE);
try {
stmt.bindf("is", root.getWcId(), localRelPath);
stmt.done();
} finally {
stmt.reset();
}
}
public enum RevertInfo {
reverted,
conflictOld,
conflictNew,
conflictWorking,
propReject,
copiedHere,
kind
}
public static Map<File, SVNWCDbKind> readRevertCopiedChildren(SVNWCContext context, File localAbsPath) throws SVNException {
Map<File, SVNWCDbKind> result = new TreeMap<File, ISVNWCDb.SVNWCDbKind>(new Comparator<File>() {
@SuppressWarnings("unchecked")
public int compare(File o1, File o2) {
String path1 = o1.getAbsolutePath();
String path2 = o2.getAbsolutePath();
return -SVNPathUtil.PATH_COMPARATOR.compare(path1, path2);
}
});
SVNWCDb db = (SVNWCDb) context.getDb();
DirParsedInfo dirInfo = db.obtainWcRoot(localAbsPath);
File localRelpath = dirInfo.localRelPath;
SVNWCDbRoot root = dirInfo.wcDbDir.getWCRoot();
root.getSDb().getTemporaryDb().beginTransaction(SqlJetTransactionMode.READ_ONLY);
SVNSqlJetStatement stmt = null;
try {
stmt = root.getSDb().getTemporaryDb().getStatement(SVNWCDbStatements.SELECT_REVERT_LIST_COPIED_CHILDREN);
stmt.bindf("si", localRelpath, SVNWCUtils.relpathDepth(localRelpath));
while(stmt.next()) {
String relpath = getColumnText(stmt, REVERT_LIST__Fields.local_relpath);
File childFile = SVNFileUtil.createFilePath(root.getAbsPath(), relpath);
result.put(childFile, getColumnKind(stmt, REVERT_LIST__Fields.kind));
}
} finally {
reset(stmt);
root.getSDb().getTemporaryDb().commit();
}
return result;
}
public static Structure<RevertInfo> readRevertInfo(SVNWCContext context, File localAbsPath) throws SVNException {
SVNWCDb db = (SVNWCDb) context.getDb();
DirParsedInfo dirInfo = db.obtainWcRoot(localAbsPath);
File localRelpath = dirInfo.localRelPath;
SVNWCDbRoot root = dirInfo.wcDbDir.getWCRoot();
root.getSDb().getTemporaryDb().beginTransaction(SqlJetTransactionMode.WRITE);
Structure<RevertInfo> result = Structure.obtain(RevertInfo.class);
result.set(RevertInfo.kind, SVNWCDbKind.Unknown);
result.set(RevertInfo.reverted, false);
result.set(RevertInfo.copiedHere, false);
try {
/**
* SELECT conflict_old, conflict_new, conflict_working, prop_reject, notify,
* actual, op_depth, repos_id, kind
* FROM revert_list
* WHERE local_relpath = ?1
* ORDER BY actual DESC
*/
SVNSqlJetStatement stmt = new SVNSqlJetSelectStatement(root.getSDb().getTemporaryDb(), SVNWCDbSchema.REVERT_LIST) {
@Override
protected ISqlJetCursor openCursor() throws SVNException {
try {
return super.openCursor().reverse();
} catch (SqlJetException e) {
SVNSqlJetDb.createSqlJetError(e);
}
return null;
}
};
stmt.bindf("s", localRelpath);
boolean haveRow = stmt.next();
if (haveRow) {
boolean isActual = getColumnBoolean(stmt, REVERT_LIST__Fields.actual);
boolean anotherRow = false;
if (isActual) {
result.set(RevertInfo.reverted, !isColumnNull(stmt, REVERT_LIST__Fields.notify));
if (!isColumnNull(stmt, REVERT_LIST__Fields.conflict_old)) {
String path = getColumnText(stmt, REVERT_LIST__Fields.conflict_old);
result.set(RevertInfo.conflictOld, SVNFileUtil.createFilePath(root.getAbsPath(), path));
}
if (!isColumnNull(stmt, REVERT_LIST__Fields.conflict_new)) {
String path = getColumnText(stmt, REVERT_LIST__Fields.conflict_new);
result.set(RevertInfo.conflictNew, SVNFileUtil.createFilePath(root.getAbsPath(), path));
}
if (!isColumnNull(stmt, REVERT_LIST__Fields.conflict_working)) {
String path = getColumnText(stmt, REVERT_LIST__Fields.conflict_working);
result.set(RevertInfo.conflictWorking, SVNFileUtil.createFilePath(root.getAbsPath(), path));
}
if (!isColumnNull(stmt, REVERT_LIST__Fields.prop_reject)) {
String path = getColumnText(stmt, REVERT_LIST__Fields.prop_reject);
result.set(RevertInfo.propReject, SVNFileUtil.createFilePath(root.getAbsPath(), path));
}
anotherRow = stmt.next();
}
if (!isActual || anotherRow) {
result.set(RevertInfo.reverted, true);
if (!isColumnNull(stmt, REVERT_LIST__Fields.repos_id)) {
long opDepth = getColumnInt64(stmt, REVERT_LIST__Fields.op_depth);
result.set(RevertInfo.copiedHere, opDepth == SVNWCUtils.relpathDepth(localRelpath));
}
result.set(RevertInfo.kind, getColumnKind(stmt, REVERT_LIST__Fields.kind));
}
}
reset(stmt);
if (haveRow) {
stmt = new SVNSqlJetDeleteStatement(root.getSDb().getTemporaryDb(), SVNWCDbSchema.REVERT_LIST);
try {
stmt.bindf("s", localRelpath);
stmt.done();
} finally {
stmt.reset();
}
}
} catch (SVNException e) {
root.getSDb().getTemporaryDb().rollback();
throw e;
} finally {
root.getSDb().getTemporaryDb().commit();
}
return result;
}
public static void dropRevertList(SVNWCContext context, File localAbsPath) throws SVNException {
SVNWCDb db = (SVNWCDb) context.getDb();
DirParsedInfo dirInfo = db.obtainWcRoot(localAbsPath);
SVNWCDbRoot root = dirInfo.wcDbDir.getWCRoot();
SVNSqlJetStatement stmt = new SVNWCDbCreateSchema(root.getSDb(), SVNWCDbCreateSchema.DROP_REVERT_LIST, -1);
try {
stmt.done();
} finally {
stmt.reset();
}
}
public static void notifyRevert(SVNWCContext context, File localAbsPath, ISVNEventHandler eventHandler) throws SVNException {
SVNWCDb db = (SVNWCDb) context.getDb();
DirParsedInfo dirInfo = db.obtainWcRoot(localAbsPath);
File localRelpath = dirInfo.localRelPath;
SVNWCDbRoot root = dirInfo.wcDbDir.getWCRoot();
SVNSqlJetStatement stmt = new SVNSqlJetSelectStatement(root.getSDb().getTemporaryDb(), SVNWCDbSchema.REVERT_LIST) {
@Override
protected boolean isFilterPassed() throws SVNException {
String rowPath = getColumnString(REVERT_LIST__Fields.local_relpath);
String selectPath = (String) getBind(1);
if (selectPath.equals(rowPath) || "".equals(selectPath) || rowPath.startsWith(selectPath + "/")) {
return !isColumnNull(REVERT_LIST__Fields.notify) || getColumnLong(REVERT_LIST__Fields.actual) == 0;
}
return false;
}
@Override
protected Object[] getWhere() throws SVNException {
return new Object[] {};
}
};
stmt.bindf("s", localRelpath);
try {
if (eventHandler != null) {
File previousPath = null;
while(stmt.next()) {
File notifyRelPath = getColumnPath(stmt, REVERT_LIST__Fields.local_relpath);
if (previousPath != null && notifyRelPath.equals(previousPath)) {
continue;
}
previousPath = notifyRelPath;
File notifyAbsPath = SVNFileUtil.createFilePath(root.getAbsPath(), notifyRelPath);
eventHandler.handleEvent(SVNEventFactory.createSVNEvent(notifyAbsPath, SVNNodeKind.NONE, null, -1, SVNEventAction.REVERT,
SVNEventAction.REVERT, null, null, -1, -1), -1);
}
}
} finally {
reset(stmt);
}
stmt = new SVNSqlJetDeleteStatement(root.getSDb().getTemporaryDb(), SVNWCDbSchema.REVERT_LIST) {
@Override
protected Object[] getWhere() throws SVNException {
return new Object[0];
}
@Override
protected boolean isFilterPassed() throws SVNException {
String selectPath = (String) getBind(1);
if ("".equals(selectPath)) {
return true;
}
String rowPath = getColumnString(REVERT_LIST__Fields.local_relpath);
return rowPath.equals(selectPath) || rowPath.startsWith(selectPath + "/");
}
};
try {
stmt.bindf("s", localRelpath);
stmt.done();
} finally {
stmt.reset();
}
}
}