summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/wc-checks.sql
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/wc-checks.sql')
-rw-r--r--subversion/libsvn_wc/wc-checks.sql214
1 files changed, 214 insertions, 0 deletions
diff --git a/subversion/libsvn_wc/wc-checks.sql b/subversion/libsvn_wc/wc-checks.sql
index a677270..fce7b49 100644
--- a/subversion/libsvn_wc/wc-checks.sql
+++ b/subversion/libsvn_wc/wc-checks.sql
@@ -75,3 +75,217 @@ BEGIN
SELECT RAISE(FAIL, 'WC DB validity check 04 failed');
END;
+-- STMT_STATIC_VERIFY
+SELECT local_relpath, op_depth, 1, 'Invalid parent relpath set in NODES'
+FROM nodes n WHERE local_relpath != ''
+ AND (parent_relpath IS NULL
+ OR NOT IS_STRICT_DESCENDANT_OF(local_relpath, parent_relpath)
+ OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1)
+
+UNION ALL
+
+SELECT local_relpath, -1, 2, 'Invalid parent relpath set in ACTUAL'
+FROM actual_node a WHERE local_relpath != ''
+ AND (parent_relpath IS NULL
+ OR NOT IS_STRICT_DESCENDANT_OF(local_relpath, parent_relpath)
+ OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1)
+
+UNION ALL
+
+/* All ACTUAL nodes must have an equivalent NODE in NODES
+ or be only one level deep (delete-delete tc) */
+SELECT local_relpath, -1, 10, 'No ancestor in ACTUAL'
+FROM actual_node a WHERE local_relpath != ''
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=a.wc_id
+ AND i.local_relpath=a.parent_relpath)
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=a.wc_id
+ AND i.local_relpath=a.local_relpath)
+
+UNION ALL
+/* Verify if the ACTUAL data makes sense for the related node.
+ Only conflict data is valid if there is none */
+SELECT a.local_relpath, -1, 11, 'Bad or Unneeded actual data'
+FROM actual_node a
+LEFT JOIN nodes n on n.wc_id = a.wc_id AND n.local_relpath = a.local_relpath
+ AND n.op_depth = (SELECT MAX(op_depth) from nodes i
+ WHERE i.wc_id=a.wc_id AND i.local_relpath=a.local_relpath)
+WHERE (a.properties IS NOT NULL
+ AND (n.presence IS NULL
+ OR n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)))
+ OR (a.changelist IS NOT NULL AND (n.kind IS NOT NULL AND n.kind != MAP_FILE))
+ OR (a.conflict_data IS NULL AND a.properties IS NULL AND a.changelist IS NULL)
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=a.wc_id
+ AND i.local_relpath=a.parent_relpath)
+
+UNION ALL
+
+/* A parent node must exist for every normal node except the root.
+ That node must exist at a lower or equal op-depth */
+SELECT local_relpath, op_depth, 20, 'No ancestor in NODES'
+FROM nodes n WHERE local_relpath != ''
+ AND file_external IS NULL
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=n.wc_id
+ AND i.local_relpath=n.parent_relpath
+ AND i.op_depth <= n.op_depth)
+
+UNION ALL
+/* If a node is not present in the working copy (normal, add, copy) it doesn't
+ have revision details stored on this record */
+SELECT local_relpath, op_depth, 21, 'Unneeded node data'
+FROM nodes
+WHERE presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
+AND (properties IS NOT NULL
+ OR checksum IS NOT NULL
+ OR depth IS NOT NULL
+ OR symlink_target IS NOT NULL
+ OR changed_revision IS NOT NULL
+ OR (changed_date IS NOT NULL AND changed_date != 0)
+ OR changed_author IS NOT NULL
+ OR translated_size IS NOT NULL
+ OR last_mod_time IS NOT NULL
+ OR dav_cache IS NOT NULL
+ OR file_external IS NOT NULL
+ OR inherited_props IS NOT NULL)
+
+UNION ALL
+/* base-deleted nodes don't have a repository location. They are just
+ shadowing without a replacement */
+SELECT local_relpath, op_depth, 22, 'Unneeded base-deleted node data'
+FROM nodes
+WHERE presence IN (MAP_BASE_DELETED)
+AND (repos_id IS NOT NULL
+ OR repos_path IS NOT NULL
+ OR revision IS NOT NULL)
+
+UNION ALL
+/* Verify if type specific data is set (or not set for wrong type) */
+SELECT local_relpath, op_depth, 23, 'Kind specific data invalid on normal'
+FROM nodes
+WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+AND (kind IS NULL
+ OR (repos_path IS NULL
+ AND (properties IS NOT NULL
+ OR changed_revision IS NOT NULL
+ OR changed_author IS NOT NULL
+ OR (changed_date IS NOT NULL AND changed_date != 0)))
+ OR (CASE WHEN kind = MAP_FILE AND repos_path IS NOT NULL
+ THEN checksum IS NULL
+ ELSE checksum IS NOT NULL END)
+ OR (CASE WHEN kind = MAP_DIR THEN depth IS NULL
+ ELSE depth IS NOT NULL END)
+ OR (CASE WHEN kind = MAP_SYMLINK THEN symlink_target IS NULL
+ ELSE symlink_target IS NOT NULL END))
+
+UNION ALL
+/* Local-adds are always their own operation (read: they don't have
+ op-depth descendants, nor are op-depth descendants */
+SELECT local_relpath, op_depth, 24, 'Invalid op-depth for local add'
+FROM nodes
+WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND repos_path IS NULL
+ AND op_depth != relpath_depth(local_relpath)
+
+UNION ALL
+/* op-depth descendants are only valid if they have a direct parent
+ node at the same op-depth. Only certain types allow further
+ descendants */
+SELECT local_relpath, op_depth, 25, 'Node missing op-depth ancestor'
+FROM nodes n
+WHERE op_depth < relpath_depth(local_relpath)
+ AND file_external IS NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes p
+ WHERE p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
+ AND p.op_depth=n.op_depth
+ AND (p.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ OR (p.presence IN (MAP_BASE_DELETED, MAP_NOT_PRESENT)
+ AND n.presence = MAP_BASE_DELETED)))
+
+UNION ALL
+/* Present op-depth descendants have the repository location implied by their
+ ancestor */
+SELECT n.local_relpath, n.op_depth, 26, 'Copied descendant mismatch'
+FROM nodes n
+JOIN nodes p
+ ON p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
+ AND n.op_depth=p.op_depth
+WHERE n.op_depth > 0 AND n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND (n.repos_id != p.repos_id
+ OR n.repos_path !=
+ RELPATH_SKIP_JOIN(n.parent_relpath, p.repos_path, n.local_relpath)
+ OR n.revision != p.revision
+ OR p.kind != MAP_DIR
+ OR n.moved_here IS NOT p.moved_here)
+
+UNION ALL
+/* Only certain presence values are valid as op-root.
+ Note that the wc-root always has presence normal or incomplete */
+SELECT n.local_relpath, n.op_depth, 27, 'Invalid op-root presence'
+FROM nodes n
+WHERE n.op_depth = relpath_depth(local_relpath)
+ AND presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE, MAP_BASE_DELETED)
+
+UNION ALL
+/* If a node is shadowed, all its present op-depth descendants
+ must be shadowed at the same op-depth as well */
+SELECT n.local_relpath, s.op_depth, 28, 'Incomplete shadowing'
+FROM nodes n
+JOIN nodes s ON s.wc_id=n.wc_id AND s.local_relpath=n.local_relpath
+ AND s.op_depth = relpath_depth(s.local_relpath)
+ AND s.op_depth = (SELECT MIN(op_depth) FROM nodes d
+ WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+ AND d.op_depth > n.op_depth)
+WHERE n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND EXISTS(SELECT 1
+ FROM nodes dn
+ WHERE dn.wc_id=n.wc_id AND dn.op_depth=n.op_depth
+ AND dn.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND IS_STRICT_DESCENDANT_OF(dn.local_relpath, n.local_relpath)
+ AND dn.file_external IS NULL
+ AND NOT EXISTS(SELECT 1
+ FROM nodes ds
+ WHERE ds.wc_id=n.wc_id AND ds.op_depth=s.op_depth
+ AND ds.local_relpath=dn.local_relpath))
+
+UNION ALL
+/* A base-delete is only valid if it directly deletes a present node */
+SELECT s.local_relpath, s.op_depth, 29, 'Invalid base-delete'
+FROM nodes s
+LEFT JOIN nodes n ON n.wc_id=s.wc_id AND n.local_relpath=s.local_relpath
+ AND n.op_depth = (SELECT MAX(op_depth) FROM nodes d
+ WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+ AND d.op_depth < s.op_depth)
+WHERE s.presence = MAP_BASE_DELETED
+ AND (n.presence IS NULL
+ OR n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
+ /*OR n.kind != s.kind*/)
+
+UNION ALL
+/* Moves are stored in the working layers, not in BASE */
+SELECT n.local_relpath, n.op_depth, 30, 'Invalid data for BASE'
+FROM nodes n
+WHERE n.op_depth = 0
+ AND (n.moved_to IS NOT NULL
+ OR n.moved_here IS NOT NULL)
+
+UNION ALL
+/* If moved_here is set on an op-root, there must be a proper moved_to */
+SELECT d.local_relpath, d.op_depth, 60, 'Moved here without origin'
+FROM nodes d
+WHERE d.op_depth = relpath_depth(d.local_relpath)
+ AND d.moved_here IS NOT NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes s
+ WHERE s.wc_id = d.wc_id AND s.moved_to = d.local_relpath)
+
+UNION ALL
+/* If moved_to is set there should be an moved op root at the target */
+SELECT s.local_relpath, s.op_depth, 61, 'Moved to without target'
+FROM nodes s
+WHERE s.moved_to IS NOT NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes d
+ WHERE d.wc_id = s.wc_id AND d.local_relpath = s.moved_to
+ AND d.op_depth = relpath_depth(d.local_relpath)
+ AND d.moved_here =1 AND d.repos_path IS NOT NULL)