]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_wc/wc-checks.sql
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_wc / wc-checks.sql
1 /* wc-checks.sql -- trigger-based checks for the wc-metadata database.
2  *     This is intended for use with SQLite 3
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24
25 -- STMT_VERIFICATION_TRIGGERS
26
27 /* ------------------------------------------------------------------------- */
28
29 CREATE TEMPORARY TRIGGER no_repository_updates BEFORE UPDATE ON repository
30 BEGIN
31   SELECT RAISE(FAIL, 'Updates to REPOSITORY are not allowed.');
32 END;
33
34 /* ------------------------------------------------------------------------- */
35
36 /* Verify: on every NODES row: parent_relpath is parent of local_relpath */
37 CREATE TEMPORARY TRIGGER validation_01 BEFORE INSERT ON nodes
38 WHEN NOT ((new.local_relpath = '' AND new.parent_relpath IS NULL)
39           OR (relpath_depth(new.local_relpath)
40               = relpath_depth(new.parent_relpath) + 1))
41 BEGIN
42   SELECT RAISE(FAIL, 'WC DB validity check 01 failed');
43 END;
44
45 /* Verify: on every NODES row: its op-depth <= its own depth */
46 CREATE TEMPORARY TRIGGER validation_02 BEFORE INSERT ON nodes
47 WHEN NOT new.op_depth <= relpath_depth(new.local_relpath)
48 BEGIN
49   SELECT RAISE(FAIL, 'WC DB validity check 02 failed');
50 END;
51
52 /* Verify: on every NODES row: it is an op-root or it has a parent with the
53     sames op-depth. (Except when the node is a file external) */
54 CREATE TEMPORARY TRIGGER validation_03 BEFORE INSERT ON nodes
55 WHEN NOT (
56     (new.op_depth = relpath_depth(new.local_relpath))
57     OR
58     (EXISTS (SELECT 1 FROM nodes
59               WHERE wc_id = new.wc_id AND op_depth = new.op_depth
60                 AND local_relpath = new.parent_relpath))
61   )
62  AND NOT (new.file_external IS NOT NULL AND new.op_depth = 0)
63 BEGIN
64   SELECT RAISE(FAIL, 'WC DB validity check 03 failed');
65 END;
66
67 /* Verify: on every ACTUAL row (except root): a NODES row exists at its
68  * parent path. */
69 CREATE TEMPORARY TRIGGER validation_04 BEFORE INSERT ON actual_node
70 WHEN NOT (new.local_relpath = ''
71           OR EXISTS (SELECT 1 FROM nodes
72                        WHERE wc_id = new.wc_id
73                          AND local_relpath = new.parent_relpath))
74 BEGIN
75   SELECT RAISE(FAIL, 'WC DB validity check 04 failed');
76 END;
77
78 -- STMT_STATIC_VERIFY
79 SELECT local_relpath, op_depth, 1, 'Invalid parent relpath set in NODES'
80 FROM nodes n WHERE local_relpath != ''
81  AND (parent_relpath IS NULL
82       OR NOT IS_STRICT_DESCENDANT_OF(local_relpath, parent_relpath)
83       OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1)
84
85 UNION ALL
86
87 SELECT local_relpath, -1, 2, 'Invalid parent relpath set in ACTUAL'
88 FROM actual_node a WHERE local_relpath != ''
89  AND (parent_relpath IS NULL
90       OR NOT IS_STRICT_DESCENDANT_OF(local_relpath, parent_relpath)
91       OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1)
92
93 UNION ALL
94
95 /* All ACTUAL nodes must have an equivalent NODE in NODES
96    or be only one level deep (delete-delete tc) */
97 SELECT local_relpath, -1, 10, 'No ancestor in ACTUAL'
98 FROM actual_node a WHERE local_relpath != ''
99  AND NOT EXISTS(SELECT 1 from nodes i
100                 WHERE i.wc_id=a.wc_id
101                   AND i.local_relpath=a.parent_relpath)
102  AND NOT EXISTS(SELECT 1 from nodes i
103                 WHERE i.wc_id=a.wc_id
104                   AND i.local_relpath=a.local_relpath)
105
106 UNION ALL
107 /* Verify if the ACTUAL data makes sense for the related node.
108    Only conflict data is valid if there is none */
109 SELECT a.local_relpath, -1, 11, 'Bad or Unneeded actual data'
110 FROM actual_node a
111 LEFT JOIN nodes n on n.wc_id = a.wc_id AND n.local_relpath = a.local_relpath
112    AND n.op_depth = (SELECT MAX(op_depth) from nodes i
113                      WHERE i.wc_id=a.wc_id AND i.local_relpath=a.local_relpath)
114 WHERE (a.properties IS NOT NULL
115        AND (n.presence IS NULL
116             OR n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)))
117    OR (a.changelist IS NOT NULL AND (n.kind IS NOT NULL AND n.kind != MAP_FILE))
118    OR (a.conflict_data IS NULL AND a.properties IS NULL AND a.changelist IS NULL)
119  AND NOT EXISTS(SELECT 1 from nodes i
120                 WHERE i.wc_id=a.wc_id
121                   AND i.local_relpath=a.parent_relpath)
122
123 UNION ALL
124
125 /* A parent node must exist for every normal node except the root.
126    That node must exist at a lower or equal op-depth */
127 SELECT local_relpath, op_depth, 20, 'No ancestor in NODES'
128 FROM nodes n WHERE local_relpath != ''
129  AND file_external IS NULL
130  AND NOT EXISTS(SELECT 1 from nodes i
131                 WHERE i.wc_id=n.wc_id
132                   AND i.local_relpath=n.parent_relpath
133                   AND i.op_depth <= n.op_depth)
134
135 UNION ALL
136 /* If a node is not present in the working copy (normal, add, copy) it doesn't
137    have revision details stored on this record */
138 SELECT local_relpath, op_depth, 21, 'Unneeded node data'
139 FROM nodes
140 WHERE presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
141 AND (properties IS NOT NULL
142      OR checksum IS NOT NULL
143      OR depth IS NOT NULL
144      OR symlink_target IS NOT NULL
145      OR changed_revision IS NOT NULL
146      OR (changed_date IS NOT NULL AND changed_date != 0)
147      OR changed_author IS NOT NULL
148      OR translated_size IS NOT NULL
149      OR last_mod_time IS NOT NULL
150      OR dav_cache IS NOT NULL
151      OR file_external IS NOT NULL
152      OR inherited_props IS NOT NULL)
153
154 UNION ALL
155 /* base-deleted nodes don't have a repository location. They are just
156    shadowing without a replacement */
157 SELECT local_relpath, op_depth, 22, 'Unneeded base-deleted node data'
158 FROM nodes
159 WHERE presence IN (MAP_BASE_DELETED)
160 AND (repos_id IS NOT NULL
161      OR repos_path IS NOT NULL
162      OR revision IS NOT NULL)
163
164 UNION ALL
165 /* Verify if type specific data is set (or not set for wrong type) */
166 SELECT local_relpath, op_depth, 23, 'Kind specific data invalid on normal'
167 FROM nodes
168 WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
169 AND (kind IS NULL
170      OR (repos_path IS NULL
171          AND (properties IS NOT NULL
172               OR changed_revision IS NOT NULL
173               OR changed_author IS NOT NULL
174               OR (changed_date IS NOT NULL AND changed_date != 0)))
175      OR (CASE WHEN kind = MAP_FILE AND repos_path IS NOT NULL
176                                    THEN checksum IS NULL
177                                    ELSE checksum IS NOT NULL END)
178      OR (CASE WHEN kind = MAP_DIR THEN depth IS NULL
179                                   ELSE depth IS NOT NULL END)
180      OR (CASE WHEN kind = MAP_SYMLINK THEN symlink_target IS NULL
181                                       ELSE symlink_target IS NOT NULL END))
182
183 UNION ALL
184 /* Local-adds are always their own operation (read: they don't have
185    op-depth descendants, nor are op-depth descendants */
186 SELECT local_relpath, op_depth, 24, 'Invalid op-depth for local add'
187 FROM nodes
188 WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
189   AND repos_path IS NULL
190   AND op_depth != relpath_depth(local_relpath)
191
192 UNION ALL
193 /* op-depth descendants are only valid if they have a direct parent
194    node at the same op-depth. Only certain types allow further
195    descendants */
196 SELECT local_relpath, op_depth, 25, 'Node missing op-depth ancestor'
197 FROM nodes n
198 WHERE op_depth < relpath_depth(local_relpath)
199   AND file_external IS NULL
200   AND NOT EXISTS(SELECT 1 FROM nodes p
201                  WHERE p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
202                    AND p.op_depth=n.op_depth
203                    AND (p.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
204                         OR (p.presence IN (MAP_BASE_DELETED, MAP_NOT_PRESENT)
205                             AND n.presence = MAP_BASE_DELETED)))
206
207 UNION ALL
208 /* Present op-depth descendants have the repository location implied by their
209    ancestor */
210 SELECT n.local_relpath, n.op_depth, 26, 'Copied descendant mismatch'
211 FROM nodes n
212 JOIN nodes p
213   ON p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
214   AND n.op_depth=p.op_depth
215 WHERE n.op_depth > 0 AND n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
216    AND (n.repos_id != p.repos_id
217         OR n.repos_path !=
218            RELPATH_SKIP_JOIN(n.parent_relpath, p.repos_path, n.local_relpath)
219         OR n.revision != p.revision
220         OR p.kind != MAP_DIR
221         OR n.moved_here IS NOT p.moved_here)
222
223 UNION ALL
224 /* Only certain presence values are valid as op-root.
225    Note that the wc-root always has presence normal or incomplete */
226 SELECT n.local_relpath, n.op_depth, 27, 'Invalid op-root presence'
227 FROM nodes n
228 WHERE n.op_depth = relpath_depth(local_relpath)
229   AND presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE, MAP_BASE_DELETED)
230
231 UNION ALL
232 /* If a node is shadowed, all its present op-depth descendants
233    must be shadowed at the same op-depth as well */
234 SELECT n.local_relpath, s.op_depth, 28, 'Incomplete shadowing'
235 FROM nodes n
236 JOIN nodes s ON s.wc_id=n.wc_id AND s.local_relpath=n.local_relpath
237  AND s.op_depth = relpath_depth(s.local_relpath)
238  AND s.op_depth = (SELECT MIN(op_depth) FROM nodes d
239                    WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
240                      AND d.op_depth > n.op_depth)
241 WHERE n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
242   AND EXISTS(SELECT 1
243              FROM nodes dn
244              WHERE dn.wc_id=n.wc_id AND dn.op_depth=n.op_depth
245                AND dn.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
246                AND IS_STRICT_DESCENDANT_OF(dn.local_relpath, n.local_relpath)
247                AND dn.file_external IS NULL
248                AND NOT EXISTS(SELECT 1
249                               FROM nodes ds
250                               WHERE ds.wc_id=n.wc_id AND ds.op_depth=s.op_depth
251                                 AND ds.local_relpath=dn.local_relpath))
252
253 UNION ALL
254 /* A base-delete is only valid if it directly deletes a present node */
255 SELECT s.local_relpath, s.op_depth, 29, 'Invalid base-delete'
256 FROM nodes s
257 LEFT JOIN nodes n ON n.wc_id=s.wc_id AND n.local_relpath=s.local_relpath
258  AND n.op_depth = (SELECT MAX(op_depth) FROM nodes d
259                    WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
260                      AND d.op_depth < s.op_depth)
261 WHERE s.presence = MAP_BASE_DELETED
262   AND (n.presence IS NULL
263        OR n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
264        /*OR n.kind != s.kind*/)
265
266 UNION ALL
267 /* Moves are stored in the working layers, not in BASE */
268 SELECT n.local_relpath, n.op_depth, 30, 'Invalid data for BASE'
269 FROM nodes n
270 WHERE n.op_depth = 0
271   AND (n.moved_to IS NOT NULL
272        OR n.moved_here IS NOT NULL)
273
274 UNION ALL
275 /* If moved_here is set on an op-root, there must be a proper moved_to */
276 SELECT d.local_relpath, d.op_depth, 60, 'Moved here without origin'
277 FROM nodes d
278 WHERE d.op_depth = relpath_depth(d.local_relpath)
279   AND d.moved_here IS NOT NULL
280   AND NOT EXISTS(SELECT 1 FROM nodes s
281                  WHERE s.wc_id = d.wc_id AND s.moved_to = d.local_relpath)
282
283 UNION ALL
284 /* If moved_to is set there should be an moved op root at the target */
285 SELECT s.local_relpath, s.op_depth, 61, 'Moved to without target'
286 FROM nodes s
287 WHERE s.moved_to IS NOT NULL
288   AND NOT EXISTS(SELECT 1 FROM nodes d
289                  WHERE d.wc_id = s.wc_id AND d.local_relpath = s.moved_to
290                    AND d.op_depth = relpath_depth(d.local_relpath)
291                    AND d.moved_here =1 AND d.repos_path IS NOT NULL)