package org.tmatesoft.svn.core.internal.wc17.db; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnBlob; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnBoolean; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnChecksum; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnDate; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnDepth; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnInt64; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnKind; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnPath; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnPresence; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnRevNum; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getColumnText; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.getLockFromColumns; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.hasColumnProperties; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.isColumnNull; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.parseDepth; import static org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil.reset; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.sqljet.core.SqlJetTransactionMode; import org.tmatesoft.sqljet.core.table.ISqlJetCursor; import org.tmatesoft.sqljet.core.table.ISqlJetTable; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.db.SVNSqlJetDb.Mode; import org.tmatesoft.svn.core.internal.db.SVNSqlJetStatement; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc16.SVNUpdateClient16; import org.tmatesoft.svn.core.internal.wc17.SVNExternalsStore; 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.ISVNWCDb.SVNWCDbLock; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbStatus; import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb.DirParsedInfo; import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb.ReposInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.AdditionInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.DeletionInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.MovedFromInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.MovedInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.NodeInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.RepositoryInfo; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbCollectTargets; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema.LOCK__Fields; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema.NODES__Fields; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbStatements; import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver; import org.tmatesoft.svn.core.wc2.SvnTarget; import org.tmatesoft.svn.util.SVNLogType; public class SvnWcDbShared { public static final byte[] EMPTY_PROPS_BLOB = {40, 41}; public static void begingReadTransaction(SVNWCDbRoot root) throws SVNException { root.getSDb().beginTransaction(SqlJetTransactionMode.READ_ONLY); } public static void begingWriteTransaction(SVNWCDbRoot root) throws SVNException { root.getSDb().beginTransaction(SqlJetTransactionMode.WRITE); } public static void commitTransaction(SVNWCDbRoot root) throws SVNException { root.getSDb().commit(); } public static void rollbackTransaction(SVNWCDbRoot root) throws SVNException { root.getSDb().rollback(); } protected static void nodeNotFound(File absolutePath) throws SVNException { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_NOT_FOUND, "The node ''{0}'' was not found.", absolutePath); SVNErrorManager.error(err, SVNLogType.WC); } protected static void nodeIsNotInstallable(File absolutePath) throws SVNException { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_NOT_FOUND, "The node ''{0}'' is not installable.", absolutePath); SVNErrorManager.error(err, SVNLogType.WC); } protected static boolean doesNodeExists(SVNWCDbRoot wcDbRoot, File relpath) throws SVNException { SVNSqlJetStatement stmt = null; try { stmt = wcDbRoot.getSDb().getStatement(SVNWCDbStatements.DOES_NODE_EXIST); stmt.bindf("is", wcDbRoot.getWcId(), relpath); return stmt.next(); } finally { if (stmt != null) { stmt.reset(); } } } protected static void nodeNotFound(SVNWCDbRoot root, File relPath) throws SVNException { nodeNotFound(root.getAbsPath(relPath)); } protected static void sqliteError(SqlJetException e) throws SVNException { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.SQLITE_ERROR, e); SVNErrorManager.error(err, SVNLogType.WC); } protected static class Target { public Target(long wcId, String relpath) { this.relPath = relpath; this.wcId = wcId; } public String relPath; public long wcId; } protected static Collection<Target> collectTargets(SVNWCDbRoot root, File relpath, SVNDepth depth, Collection<String> changelists) throws SVNException { SVNSqlJetStatement stmt = null; final Collection<Target> targets = new ArrayList<Target>(); try { stmt = new SVNWCDbCollectTargets(root.getSDb(), root.getWcId(), relpath, depth, changelists); while(stmt.next()) { final long wcId = getColumnInt64(stmt, NODES__Fields.wc_id); final String path = getColumnText(stmt, NODES__Fields.local_relpath); targets.add(new Target(wcId, path)); } if (depth == SVNDepth.FILES || depth == SVNDepth.IMMEDIATES) { reset(stmt); stmt = new SVNWCDbCollectTargets(root.getSDb(), root.getWcId(), relpath, SVNDepth.EMPTY, changelists); while(stmt.next()) { final long wcId = getColumnInt64(stmt, NODES__Fields.wc_id); final String path = getColumnText(stmt, NODES__Fields.local_relpath); targets.add(new Target(wcId, path)); } } } finally { reset(stmt); } return targets; } public static Structure<AdditionInfo> scanAddition(SVNWCDb db, File localAbsPath) throws SVNException { DirParsedInfo parsed = db.parseDir(localAbsPath, Mode.ReadOnly); SVNWCDbDir pdh = parsed.wcDbDir; File localRelpath = parsed.localRelPath; Structure<AdditionInfo> additionInfo = scanAddition(pdh.getWCRoot(), localRelpath); if (additionInfo.hasField(AdditionInfo.reposRootUrl)) { ReposInfo reposInfo = db.fetchReposInfo(pdh.getWCRoot().getSDb(), additionInfo.lng(AdditionInfo.reposId)); additionInfo.set(AdditionInfo.reposRootUrl, SVNURL.parseURIEncoded(reposInfo.reposRootUrl)); additionInfo.set(AdditionInfo.reposUuid, reposInfo.reposUuid); } if (additionInfo.hasField(AdditionInfo.originalRootUrl) && additionInfo.lng(AdditionInfo.originalReposId) >= 0) { ReposInfo reposInfo = db.fetchReposInfo(pdh.getWCRoot().getSDb(), additionInfo.lng(AdditionInfo.originalReposId)); additionInfo.set(AdditionInfo.originalRootUrl, SVNURL.parseURIEncoded(reposInfo.reposRootUrl)); additionInfo.set(AdditionInfo.originalUuid, reposInfo.reposUuid); } return additionInfo; } public static Structure<MovedInfo> scanMoved(SVNWCDb db, File localAbsPath) throws SVNException { final Structure<MovedInfo> result = Structure.obtain(MovedInfo.class); final DirParsedInfo parsed = db.parseDir(localAbsPath, Mode.ReadOnly); final SVNWCDbDir pdh = parsed.wcDbDir; final File localRelpath = parsed.localRelPath; final SVNWCDbRoot root = pdh.getWCRoot(); final Structure<AdditionInfo> additionInfo = scanAddition(pdh.getWCRoot(), localRelpath, AdditionInfo.values()); if (additionInfo.get(AdditionInfo.status) != SVNWCDbStatus.MovedHere || additionInfo.get(AdditionInfo.movedFromRelPath) == null) { final SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_UNEXPECTED_STATUS, "Path ''{0}'' was not moved here", localAbsPath); SVNErrorManager.error(err, SVNLogType.WC); } result.set(MovedInfo.opRootAbsPath, additionInfo.get(AdditionInfo.opRootAbsPath)); result.set(MovedInfo.movedFromAbsPath, root.getAbsPath(additionInfo.<File>get(AdditionInfo.movedFromRelPath))); result.set(MovedInfo.movedFromOpRootAbsPath, root.getAbsPath(additionInfo.<File>get(AdditionInfo.movedFromOpRootRelPath))); long movedFromOpDepth = additionInfo.lng(AdditionInfo.movedFromOpDepth); File tmp = additionInfo.<File>get(AdditionInfo.movedFromOpRootRelPath); while(SVNWCUtils.relpathDepth(tmp) > movedFromOpDepth) { tmp = SVNFileUtil.getFileDir(tmp); } result.set(MovedInfo.movedFromDeleteAbsPath, root.getAbsPath(tmp)); return result; } protected static Structure<AdditionInfo> scanAddition(SVNWCDbRoot root, File localRelpath, AdditionInfo... fields) throws SVNException { Structure<AdditionInfo> info = Structure.obtain(AdditionInfo.class, fields); info.set(AdditionInfo.originalRevision, SVNWCDb.INVALID_REVNUM); info.set(AdditionInfo.originalReposId, SVNWCDb.INVALID_REPOS_ID); info.set(AdditionInfo.movedFromOpDepth, 0); begingReadTransaction(root); File buildRelpath = SVNFileUtil.createFilePath(""); File currentRelpath = localRelpath; SVNSqlJetStatement stmt = null; try { SVNWCDbStatus presence; File reposPrefixPath = SVNFileUtil.createFilePath(""); int i; stmt = root.getSDb().getStatement(SVNWCDbStatements.SELECT_WORKING_NODE); stmt.bindf("is", root.getWcId(), localRelpath); if (!stmt.next()) { reset(stmt); nodeNotFound(root, localRelpath); } presence = getColumnPresence(stmt); long opDepth = getColumnInt64(stmt, SVNWCDbSchema.NODES__Fields.op_depth); if (opDepth == 0 || (presence != SVNWCDbStatus.Normal && presence != SVNWCDbStatus.Incomplete)) { reset(stmt); SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_UNEXPECTED_STATUS, "Expected node ''{0}'' to be added.", root.getAbsPath(localRelpath)); SVNErrorManager.error(err, SVNLogType.WC); } info.set(AdditionInfo.originalRevision, getColumnRevNum(stmt, NODES__Fields.revision)); info.set(AdditionInfo.status, SVNWCDbStatus.Added); currentRelpath = localRelpath; for (i = SVNWCUtils.relpathDepth(localRelpath); i > opDepth; --i) { reposPrefixPath = SVNFileUtil.createFilePath(SVNFileUtil.createFilePath(SVNFileUtil.getFileName(currentRelpath)), reposPrefixPath); currentRelpath = SVNFileUtil.getFileDir(currentRelpath); } info.set(AdditionInfo.opRootRelPath, currentRelpath); info.set(AdditionInfo.opRootAbsPath, root.getAbsPath(currentRelpath)); if (info.hasField(AdditionInfo.originalReposRelPath) || info.hasField(AdditionInfo.originalRootUrl) || info.hasField(AdditionInfo.originalUuid) || (info.hasField(AdditionInfo.originalRevision) && info.lng(AdditionInfo.originalRevision) == SVNWCDb.INVALID_REVNUM) || info.hasField(AdditionInfo.status)) { if (!localRelpath.equals(currentRelpath)) { reset(stmt); stmt.bindf("is", root.getWcId(), currentRelpath); if (!stmt.next()) { reset(stmt); nodeNotFound(root, currentRelpath); } if (info.hasField(AdditionInfo.originalRevision) && info.lng(AdditionInfo.originalRevision) == SVNWCDb.INVALID_REVNUM) info.set(AdditionInfo.originalRevision, getColumnRevNum(stmt, NODES__Fields.revision)); } info.set(AdditionInfo.originalReposRelPath, getColumnPath(stmt, NODES__Fields.repos_path)); if (!isColumnNull(stmt, NODES__Fields.repos_id) && ( info.hasField(AdditionInfo.status) || info.hasField(AdditionInfo.originalReposId) || info.hasField(AdditionInfo.movedFromRelPath) || info.hasField(AdditionInfo.movedFromOpRootRelPath))) { info.set(AdditionInfo.originalReposId, getColumnInt64(stmt, NODES__Fields.repos_id)); final boolean movedHere = getColumnBoolean(stmt, NODES__Fields.moved_here); if (movedHere) { info.set(AdditionInfo.status, SVNWCDbStatus.MovedHere); } else { info.set(AdditionInfo.status, SVNWCDbStatus.Copied); } if (movedHere && (info.hasField(AdditionInfo.movedFromRelPath) || info.hasField(AdditionInfo.movedFromOpRootRelPath))) { final Structure<MovedFromInfo> movedFromInfo = getMovedFromInfo(root, currentRelpath, localRelpath); if (movedFromInfo.hasValue(MovedFromInfo.opDepth)) { info.set(AdditionInfo.movedFromOpDepth, movedFromInfo.lng(MovedFromInfo.opDepth)); } info.set(AdditionInfo.movedFromOpRootRelPath, movedFromInfo.get(MovedFromInfo.movedFromOpRootRelPath)); info.set(AdditionInfo.movedFromRelPath, movedFromInfo.get(MovedFromInfo.movedFromRelPath)); } } } while (true) { reset(stmt); reposPrefixPath = SVNFileUtil.createFilePath(SVNFileUtil.createFilePath(SVNFileUtil.getFileName(currentRelpath)), reposPrefixPath); currentRelpath = SVNFileUtil.getFileDir(currentRelpath); stmt.bindf("is", root.getWcId(), currentRelpath); if (!stmt.next()) { break; } opDepth = getColumnInt64(stmt, NODES__Fields.op_depth); for (i = SVNWCUtils.relpathDepth(currentRelpath); i > opDepth; i--) { reposPrefixPath = SVNFileUtil.createFilePath(SVNFileUtil.createFilePath(SVNFileUtil.getFileName(currentRelpath)), reposPrefixPath); currentRelpath = SVNFileUtil.getFileDir(currentRelpath); } } reset(stmt); buildRelpath = reposPrefixPath; if (info.hasField(AdditionInfo.reposRelPath) || info.hasField(AdditionInfo.reposId)) { Structure<NodeInfo> baseInfo = getDepthInfo(root, currentRelpath, 0, NodeInfo.reposRelPath, NodeInfo.reposId); info.set(AdditionInfo.reposRelPath, SVNFileUtil.createFilePath(baseInfo.<File>get(NodeInfo.reposRelPath), buildRelpath)); info.set(AdditionInfo.reposId, baseInfo.lng(NodeInfo.reposId)); baseInfo.release(); } } finally { reset(stmt); commitTransaction(root); } return info; } public static Structure<MovedFromInfo> getMovedFromInfo(SVNWCDbRoot root, File movedToOpRootRelPath, File localRelPath) throws SVNException { final Structure<MovedFromInfo> result = Structure.obtain(MovedFromInfo.class); SVNSqlJetStatement stmt = null; try { stmt = root.getSDb().getStatement(root.getFormat() == ISVNWCDb.WC_FORMAT_17 ? SVNWCDbStatements.SELECT_MOVED_FROM_RELPATH_17 : SVNWCDbStatements.SELECT_MOVED_FROM_RELPATH); stmt.bindf("is", root.getWcId(), movedToOpRootRelPath); if (!stmt.next()) { return result; } result.set(MovedFromInfo.opDepth, getColumnInt64(stmt, NODES__Fields.op_depth)); final File deleteOpRootReplpath = getColumnPath(stmt, NODES__Fields.local_relpath); result.set(MovedFromInfo.movedFromOpRootRelPath, deleteOpRootReplpath); if (movedToOpRootRelPath.equals(localRelPath)) { result.set(MovedFromInfo.movedFromRelPath, deleteOpRootReplpath); } else { final File childRelPath = SVNWCUtils.skipAncestor(movedToOpRootRelPath, localRelPath); result.set(MovedFromInfo.movedFromRelPath, SVNFileUtil.createFilePath(deleteOpRootReplpath, childRelPath)); } } finally { reset(stmt); } return result; } public static Structure<DeletionInfo> scanDeletion(SVNWCDb db, File localAbsPath) throws SVNException { DirParsedInfo parsed = db.parseDir(localAbsPath, Mode.ReadOnly); SVNWCDbDir pdh = parsed.wcDbDir; File localRelpath = parsed.localRelPath; return scanDeletion(pdh.getWCRoot(), localRelpath); } protected static Structure<DeletionInfo> scanDeletion(SVNWCDbRoot root, File localRelpath) throws SVNException { Structure<DeletionInfo> deletionInfoStructure = Structure.obtain(DeletionInfo.class); ISVNWCDb.WCDbDeletionInfo deletionInfo = root.getDb().scanDeletion(SVNFileUtil.createFilePath(root.getAbsPath(), localRelpath), ISVNWCDb.WCDbDeletionInfo.DeletionInfoField.values()); deletionInfoStructure.set(DeletionInfo.baseDelRelPath, SVNFileUtil.skipAncestor(root.getAbsPath(), deletionInfo.baseDelAbsPath)); deletionInfoStructure.set(DeletionInfo.movedToRelPath, SVNFileUtil.skipAncestor(root.getAbsPath(), deletionInfo.movedToAbsPath)); deletionInfoStructure.set(DeletionInfo.movedToOpRootRelPath, SVNFileUtil.skipAncestor(root.getAbsPath(), deletionInfo.movedToOpRootAbsPath)); deletionInfoStructure.set(DeletionInfo.workDelAbsPath, deletionInfo.workDelAbsPath); deletionInfoStructure.set(DeletionInfo.workDelRelPath, SVNFileUtil.skipAncestor(root.getAbsPath(), deletionInfo.baseDelAbsPath)); return deletionInfoStructure; // Structure<DeletionInfo> info = Structure.obtain(DeletionInfo.class); // // SVNWCDbStatus childPresence = SVNWCDbStatus.BaseDeleted; // boolean childHasBase = false; // boolean foundMovedTo = false; // long opDepth = 0, localOpDepth = 0; // File currentRelPath = localRelpath; // File childRelpath = null; // // begingReadTransaction(root); // SVNSqlJetStatement stmt = null; // try { // while (true) { // stmt = root.getSDb().getStatement(SVNWCDbStatements.SELECT_DELETION_INFO); // stmt.bindf("is", root.getWcId(), SVNFileUtil.getFilePath(currentRelPath)); // if (!stmt.next()) { // try { // if (currentRelPath == localRelpath) { // nodeNotFound(root, localRelpath); // } // if (childHasBase) { // info.set(DeletionInfo.baseDelRelPath, childRelpath); // } // break; // } finally { // reset(stmt); // } // } // // SVNSqlJetStatement baseStmt = null; // try { // SVNWCDbStatus workPresence = getColumnPresence(stmt); // if (currentRelPath.equals(localRelpath) && workPresence != SVNWCDbStatus.NotPresent && workPresence != SVNWCDbStatus.BaseDeleted) { // SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_UNEXPECTED_STATUS, "Expected node ''{0}'' to be deleted.", root.getAbsPath(localRelpath)); // SVNErrorManager.error(err, SVNLogType.WC); // } // assert (workPresence == SVNWCDbStatus.Normal || workPresence == SVNWCDbStatus.NotPresent || workPresence == SVNWCDbStatus.BaseDeleted || workPresence == SVNWCDbStatus.Incomplete); // // baseStmt = stmt.getJoinedStatement(SVN); // boolean haveBase = false; // haveBase = baseStmt != null && baseStmt.next() && !isColumnNull(baseStmt, SVNWCDbSchema.NODES__Fields.presence); // if (haveBase) { // SVNWCDbStatus basePresence = getColumnPresence(baseStmt); // assert (basePresence == SVNWCDbStatus.Normal || basePresence == SVNWCDbStatus.NotPresent || basePresence == SVNWCDbStatus.Incomplete); // if (basePresence == SVNWCDbStatus.Incomplete) { // basePresence = SVNWCDbStatus.Normal; // } // } // // // if (!foundMovedTo && !isColumnNull(stmt, SVNWCDbSchema.NODES__Fields.moved_to)) { // foundMovedTo = true; // info.set(DeletionInfo.baseDelRelPath, currentRelPath); // info.set(DeletionInfo.movedToRelPath, getColumnPath(stmt, SVNWCDbSchema.NODES__Fields.moved_to)); // } // // opDepth = getColumnInt64(stmt, NODES__Fields.op_depth); // if (currentRelPath.equals(localRelpath)) { // localOpDepth = opDepth; // } // if (!info.hasValue(DeletionInfo.workDelRelPath) && // ((opDepth < localOpDepth && opDepth > 0) || childPresence == SVNWCDbStatus.NotPresent)) { // info.set(DeletionInfo.workDelRelPath, childRelpath); // info.set(DeletionInfo.workDelAbsPath, root.getAbsPath(childRelpath)); // } // // childRelpath = currentRelPath; // childPresence = workPresence; // childHasBase = haveBase; // // currentRelPath = SVNFileUtil.getFileDir(currentRelPath); // } finally { // reset(stmt); // reset(baseStmt); // } // } // } finally { // commitTransaction(root); // reset(stmt); // } // return info; } public static Structure<NodeInfo> getBaseInfo(SVNWCDbRoot wcroot, File localRelPath, NodeInfo... fields) throws SVNException { return getDepthInfo(wcroot, localRelPath, 0, fields); } public static Structure<NodeInfo> getBaseInfo(SVNWCDb db, File localAbsPath, NodeInfo... fields) throws SVNException { DirParsedInfo parsed = db.parseDir(localAbsPath, Mode.ReadOnly); SVNWCDbDir pdh = parsed.wcDbDir; File localRelpath = parsed.localRelPath; return getDepthInfo(pdh.getWCRoot(), localRelpath, 0, fields); } public static Structure<NodeInfo> getDepthInfo(SVNWCDbRoot wcroot, File localRelPath, long opDepth, NodeInfo...fields) throws SVNException { Structure<NodeInfo> info = Structure.obtain(NodeInfo.class, fields); SVNSqlJetStatement stmt = wcroot.getSDb().getStatement(SVNWCDbStatements.SELECT_DEPTH_NODE); try { stmt.bindf("isi", wcroot.getWcId(), SVNFileUtil.getFilePath(localRelPath), opDepth); if (stmt.next()) { SVNWCDbKind node_kind = getColumnKind(stmt, NODES__Fields.kind); if (info.hasField(NodeInfo.kind)) { info.set(NodeInfo.kind, node_kind); } if (info.hasField(NodeInfo.status)) { info.set(NodeInfo.status, getColumnPresence(stmt)); } if (info.hasField(NodeInfo.reposId)) { info.set(NodeInfo.reposId, getColumnInt64(stmt, NODES__Fields.repos_id)); } if (info.hasField(NodeInfo.revision)) { info.set(NodeInfo.revision, getColumnRevNum(stmt, SVNWCDbSchema.NODES__Fields.revision)); } if (info.hasField(NodeInfo.reposRelPath)) { info.set(NodeInfo.reposRelPath, getColumnPath(stmt, SVNWCDbSchema.NODES__Fields.repos_path)); } if (info.hasField(NodeInfo.reposRootUrl) || info.hasField(NodeInfo.reposUuid)) { if (isColumnNull(stmt, SVNWCDbSchema.NODES__Fields.repos_id)) { if (info.hasField(NodeInfo.reposRootUrl)) { info.set(NodeInfo.reposRootUrl,null); } if (info.hasField(NodeInfo.reposUuid)) { info.set(NodeInfo.reposUuid,null); } } else { Structure<RepositoryInfo> repositoryInfo = wcroot.getDb().fetchRepositoryInfo(wcroot.getSDb(), getColumnInt64(stmt, SVNWCDbSchema.NODES__Fields.repos_id)); repositoryInfo. from(RepositoryInfo.reposRootUrl, RepositoryInfo.reposUuid). into(info, NodeInfo.reposRootUrl, NodeInfo.reposUuid); repositoryInfo.release(); } } if (info.hasField(NodeInfo.changedRev)) { info.set(NodeInfo.changedRev, getColumnRevNum(stmt, SVNWCDbSchema.NODES__Fields.changed_revision)); } if (info.hasField(NodeInfo.changedDate)) { info.set(NodeInfo.changedDate, getColumnDate(stmt, SVNWCDbSchema.NODES__Fields.changed_date)); } if (info.hasField(NodeInfo.changedAuthor)) { /* Result may be NULL. */ info.set(NodeInfo.changedAuthor,getColumnText(stmt, SVNWCDbSchema.NODES__Fields.changed_author)); } if (info.hasField(NodeInfo.depth)) { if (node_kind != SVNWCDbKind.Dir) { info.set(NodeInfo.depth, SVNDepth.UNKNOWN); } else { String depth_str = getColumnText(stmt, SVNWCDbSchema.NODES__Fields.depth); if (depth_str == null) { info.set(NodeInfo.depth, SVNDepth.UNKNOWN); } else { info.set(NodeInfo.depth, parseDepth(depth_str)); } } } if (info.hasField(NodeInfo.checksum)) { if (node_kind != SVNWCDbKind.File) { info.set(NodeInfo.checksum,null); } else { try { info.set(NodeInfo.checksum, getColumnChecksum(stmt, SVNWCDbSchema.NODES__Fields.checksum)); } catch (SVNException e) { SVNErrorMessage err = SVNErrorMessage.create(e.getErrorMessage().getErrorCode(), "The node ''{0}'' has a corrupt checksum value.", wcroot.getAbsPath(localRelPath)); SVNErrorManager.error(err, SVNLogType.WC); } } } if (info.hasField(NodeInfo.target)) { if (node_kind != SVNWCDbKind.Symlink) info.set(NodeInfo.target,null); else info.set(NodeInfo.target, getColumnPath(stmt, SVNWCDbSchema.NODES__Fields.symlink_target)); } if (info.hasField(NodeInfo.updateRoot)) { info.set(NodeInfo.updateRoot, getColumnText(stmt, SVNWCDbSchema.NODES__Fields.file_external) != null); } if (info.hasField(NodeInfo.hadProps)) { info.set(NodeInfo.hadProps, hasColumnProperties(stmt, NODES__Fields.properties)); } } else { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_NOT_FOUND, "The node ''{0}'' was not found.", wcroot.getAbsPath(localRelPath)); SVNErrorManager.error(err, SVNLogType.WC); } } finally { stmt.reset(); } return info; } protected static Structure<NodeInfo> readInfo(SVNWCDbRoot wcRoot, File localRelPath, NodeInfo... fields) throws SVNException { return readInfo(wcRoot, localRelPath, false, fields); } protected static Structure<NodeInfo> readInfo(SVNWCDbRoot wcRoot, File localRelPath, boolean isAdditionMode, NodeInfo... fields) throws SVNException { Structure<NodeInfo> info = Structure.obtain(NodeInfo.class, fields); SVNSqlJetStatement stmtInfo = null; SVNSqlJetStatement stmtActual = null; try { stmtInfo = wcRoot.getSDb().getStatement(info.hasField(NodeInfo.lock) ? SVNWCDbStatements.SELECT_NODE_INFO_WITH_LOCK : SVNWCDbStatements.SELECT_NODE_INFO); stmtInfo.bindf("is", wcRoot.getWcId(), localRelPath); boolean haveInfo = stmtInfo.next(); boolean haveActual = false; if (info.hasField(NodeInfo.changelist) || info.hasField(NodeInfo.conflicted) || info.hasField(NodeInfo.propsMod)) { stmtActual = wcRoot.getSDb().getStatement(SVNWCDbStatements.SELECT_ACTUAL_NODE); stmtActual.bindf("is", wcRoot.getWcId(), localRelPath); haveActual = stmtActual.next(); } if (haveInfo) { long opDepth = getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.op_depth); SVNWCDbKind nodeKind = getColumnKind(stmtInfo, NODES__Fields.kind); if (info.hasField(NodeInfo.status)) { info.set(NodeInfo.status, getColumnPresence(stmtInfo)); if (opDepth != 0) { info.set(NodeInfo.status, SVNWCDb.getWorkingStatus(info.<SVNWCDbStatus>get(NodeInfo.status))); } } if (info.hasField(NodeInfo.kind)) { info.set(NodeInfo.kind, nodeKind); } info.set(NodeInfo.reposId, opDepth != 0 ? SVNWCDb.INVALID_REPOS_ID : getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.repos_id)); if (info.hasField(NodeInfo.revision)) { info.set(NodeInfo.revision, opDepth != 0 ? SVNWCDb.INVALID_REVNUM : getColumnRevNum(stmtInfo, SVNWCDbSchema.NODES__Fields.revision)); } if (info.hasField(NodeInfo.reposRelPath)) { info.set(NodeInfo.reposRelPath, opDepth != 0 ? null : SVNFileUtil.createFilePath(getColumnText(stmtInfo, SVNWCDbSchema.NODES__Fields.repos_path))); } if (info.hasField(NodeInfo.changedDate)) { info.set(NodeInfo.changedDate, SVNWCUtils.readDate(getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.changed_date))); } if (info.hasField(NodeInfo.changedRev)) { info.set(NodeInfo.changedRev, getColumnRevNum(stmtInfo, SVNWCDbSchema.NODES__Fields.changed_revision)); } if (info.hasField(NodeInfo.changedAuthor)) { info.set(NodeInfo.changedAuthor, getColumnText(stmtInfo, SVNWCDbSchema.NODES__Fields.changed_author)); } if (info.hasField(NodeInfo.recordedTime)) { info.set(NodeInfo.recordedTime, getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.last_mod_time)); } if (info.hasField(NodeInfo.depth)) { if (nodeKind != SVNWCDbKind.Dir) { info.set(NodeInfo.depth, SVNDepth.UNKNOWN); } else { info.set(NodeInfo.depth, getColumnDepth(stmtInfo, SVNWCDbSchema.NODES__Fields.depth)); } } if (info.hasField(NodeInfo.checksum)) { if (nodeKind != SVNWCDbKind.File) { info.set(NodeInfo.checksum, null); } else { try { info.set(NodeInfo.checksum, getColumnChecksum(stmtInfo, SVNWCDbSchema.NODES__Fields.checksum)); } catch (SVNException e) { SVNErrorMessage err = SVNErrorMessage.create(e.getErrorMessage().getErrorCode(), "The node ''{0}'' has a corrupt checksum value.", wcRoot.getAbsPath(localRelPath)); SVNErrorManager.error(err, SVNLogType.WC); } } } if (info.hasField(NodeInfo.recordedSize)) { info.set(NodeInfo.recordedSize, getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.translated_size)); } if (info.hasField(NodeInfo.target)) { info.set(NodeInfo.target, SVNFileUtil.createFilePath(getColumnText(stmtInfo, SVNWCDbSchema.NODES__Fields.symlink_target))); } if (info.hasField(NodeInfo.changelist) && haveActual) { info.set(NodeInfo.changelist, getColumnText(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.changelist)); } info.set(NodeInfo.originalReposId, opDepth == 0 ? SVNWCDb.INVALID_REPOS_ID : getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.repos_id)); if (info.hasField(NodeInfo.originalRevision)) { info.set(NodeInfo.originalRevision, opDepth == 0 ? SVNWCDb.INVALID_REVNUM : getColumnRevNum(stmtInfo, SVNWCDbSchema.NODES__Fields.revision)); } if (info.hasField(NodeInfo.originalReposRelpath)) { info.set(NodeInfo.originalReposRelpath, opDepth == 0 ? null : SVNFileUtil.createFilePath(getColumnText(stmtInfo, SVNWCDbSchema.NODES__Fields.repos_path))); } if (info.hasField(NodeInfo.propsMod)) { info.set(NodeInfo.propsMod, haveActual && !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.properties)); } if (info.hasField(NodeInfo.hadProps)) { byte[] props = getColumnBlob(stmtInfo, SVNWCDbSchema.NODES__Fields.properties); info.set(NodeInfo.hadProps, props != null && props.length > 2); } if (info.hasField(NodeInfo.conflicted)) { if (haveActual) { if (wcRoot.getFormat() == ISVNWCDb.WC_FORMAT_17) { info.set(NodeInfo.conflicted, !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.tree_conflict_data) || !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.prop_reject) || !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_old) || !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_new) || !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_working)); } else { info.set(NodeInfo.conflicted, !isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_data)); } } else { info.set(NodeInfo.conflicted, false); } } if (info.hasField(NodeInfo.lock)) { if (opDepth == 0) { final SVNSqlJetStatement stmtBaseLock = stmtInfo.getJoinedStatement(SVNWCDbSchema.LOCK.toString()); SVNWCDbLock lock = getLockFromColumns(stmtBaseLock, LOCK__Fields.lock_token, LOCK__Fields.lock_owner, LOCK__Fields.lock_comment, LOCK__Fields.lock_date); info.set(NodeInfo.lock, lock); } else { info.set(NodeInfo.lock, null); } } if (info.hasField(NodeInfo.haveWork)) { info.set(NodeInfo.haveWork, opDepth != 0); } if (info.hasField(NodeInfo.opRoot)) { info.set(NodeInfo.opRoot, opDepth > 0 && opDepth == SVNWCUtils.relpathDepth(localRelPath)); } if (info.hasField(NodeInfo.haveBase) || info.hasField(NodeInfo.haveMoreWork)) { if (info.hasField(NodeInfo.haveMoreWork)) { info.set(NodeInfo.haveMoreWork, false); } while(opDepth != 0) { haveInfo = stmtInfo.next(); if (!haveInfo) { break; } opDepth = getColumnInt64(stmtInfo, SVNWCDbSchema.NODES__Fields.op_depth); if (info.hasField(NodeInfo.haveMoreWork)) { if (opDepth > 0) { info.set(NodeInfo.haveMoreWork, true); } if (!info.hasField(NodeInfo.haveBase)) { break; } } } if (info.hasField(NodeInfo.haveBase)) { info.set(NodeInfo.haveBase, opDepth == 0); } } } else if (haveActual) { if (isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_data) && isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.tree_conflict_data) && isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.prop_reject) && isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_old) && isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_new) && isColumnNull(stmtActual, SVNWCDbSchema.ACTUAL_NODE__Fields.conflict_working)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_CORRUPT, "Corrupt data for ''{0}''", wcRoot.getAbsPath(localRelPath)); SVNErrorManager.error(err, SVNLogType.WC); } info.set(NodeInfo.conflicted, true); if (info.hasField(NodeInfo.opRoot)) { info.set(NodeInfo.opRoot, false); } if (info.hasField(NodeInfo.status)) { info.set(NodeInfo.status, SVNWCDbStatus.Normal); } if (info.hasField(NodeInfo.kind)) { info.set(NodeInfo.kind, SVNWCDbKind.Unknown); } if (info.hasField(NodeInfo.revision)) { info.set(NodeInfo.revision, SVNWCDb.INVALID_REVNUM); } info.set(NodeInfo.reposId, SVNWCDb.INVALID_REPOS_ID); if (info.hasField(NodeInfo.changedRev)) { info.set(NodeInfo.changedRev, SVNWCDb.INVALID_REVNUM); } if (info.hasField(NodeInfo.depth)) { info.set(NodeInfo.depth, SVNDepth.UNKNOWN); } if (info.hasField(NodeInfo.originalRevision)) { info.set(NodeInfo.originalRevision, SVNWCDb.INVALID_REVNUM); } if (info.hasField(NodeInfo.originalReposId)) { info.set(NodeInfo.originalReposId, SVNWCDb.INVALID_REPOS_ID); } if (info.hasField(NodeInfo.changelist)) { info.set(NodeInfo.changelist, stmtActual.getColumnString(SVNWCDbSchema.ACTUAL_NODE__Fields.changelist)); } if (info.hasField(NodeInfo.originalRevision)) info.set(NodeInfo.originalRevision, SVNWCDb.INVALID_REVNUM); } else { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_PATH_NOT_FOUND, "The node ''{0}'' was not found.", wcRoot.getAbsPath(localRelPath)); SVNErrorManager.error(err, SVNLogType.WC); } } finally { try { if (stmtInfo != null) { stmtInfo.reset(); } } catch (SVNException e) {} try { if (stmtActual != null) { stmtActual.reset(); } } catch (SVNException e) {} } return info; } public static void canonicalizeURLs(SVNWCDbRoot wcRoot, boolean updateExternalProperties, final SVNExternalsStore store, final boolean omitDefaultPort) throws SVNException { final Map<String, Object> values = new HashMap<String, Object>(); try { begingWriteTransaction(wcRoot); final ISqlJetTable repositoryTable = wcRoot.getSDb().getDb().getTable(SVNWCDbSchema.REPOSITORY.toString()); ISqlJetCursor cursor = repositoryTable.open(); while(!cursor.eof()) { final String oldUrl = cursor.getString(SVNWCDbSchema.REPOSITORY__Fields.root.toString()); final SVNURL canonicalUrl = SVNUpdateClient16.canonicalizeURL(SVNURL.parseURIEncoded(oldUrl), omitDefaultPort); if (canonicalUrl != null) { String newUrl = canonicalUrl.toString(); if (!oldUrl.equals(newUrl)) { values.put(SVNWCDbSchema.REPOSITORY__Fields.root.toString(), newUrl); cursor.updateByFieldNames(values); } } cursor.next(); } cursor.close(); } catch (SqlJetException e) { rollbackTransaction(wcRoot); } finally { commitTransaction(wcRoot); } if (updateExternalProperties) { final Map<File, SVNProperties> newPropertyValues = new HashMap<File, SVNProperties>(); SvnWcDbProperties.readPropertiesRecursively(wcRoot, new File(""), SVNDepth.INFINITY, false, false, null, new ISvnObjectReceiver<SVNProperties>() { public void receive(SvnTarget target, SVNProperties object) throws SVNException { String externalsPropertyValue = object.getStringValue(SVNProperty.EXTERNALS); if (externalsPropertyValue != null) { String newValue = SVNUpdateClient16.canonicalizeExtenrals(externalsPropertyValue, omitDefaultPort); if (!externalsPropertyValue.equals(newValue)) { object.put(SVNProperty.EXTERNALS, newValue); newPropertyValues.put(target.getFile(), object); } if (store != null) { store.addExternal(target.getFile(), externalsPropertyValue, newValue); } } } }); for (File path : newPropertyValues.keySet()) { wcRoot.getDb().opSetProps(path, newPropertyValues.get(path), null, false, null); } } } }