|
|
@@ -121,30 +121,44 @@ UPDATE "{table}" SET path = t.path FROM t WHERE "{table}".id = t.id;
|
|
|
|
|
|
def count_stale_rows_sql(table, sort_path=False):
|
|
|
"""
|
|
|
- Return SQL counting the rows in `table` whose `path` disagrees with their parent's,
|
|
|
- and (when `sort_path` is set) the rows whose `sort_path` does.
|
|
|
+ Return SQL counting the rows in `table` whose `path` disagrees with the hierarchy, and
|
|
|
+ (when `sort_path` is set) the rows whose `sort_path` does.
|
|
|
|
|
|
A reparent leaves `path` wrong, a rename leaves `sort_path` wrong, and while the
|
|
|
cascade trigger is missing either can happen without the other, so both are counted
|
|
|
- separately.
|
|
|
-
|
|
|
- This answers "does this table need rebuilding", not "how many rows are damaged". Only
|
|
|
- a row which disagrees with its own parent is counted: the descendants below it agree
|
|
|
- with their parents and are not, though they are equally stale. Treat any non-zero
|
|
|
- result as the whole table needing a rebuild, and do not use it to decide which rows to
|
|
|
- touch.
|
|
|
+ separately. Roots are checked against what `populate_paths_sql()` would give them (a
|
|
|
+ path of their own padded id, and a sort_path of their own name) and every other row
|
|
|
+ against its parent: a root has no parent to compare with, but it can still be wrong.
|
|
|
+
|
|
|
+ This answers "does this table need rebuilding", not "how many rows are damaged". Where
|
|
|
+ an object has moved, the objects below it agree with their own parent and are not
|
|
|
+ counted, though they are equally stale. Treat any non-zero result as the whole table
|
|
|
+ needing a rebuild, and do not use it to decide which rows to touch.
|
|
|
"""
|
|
|
- stale_sort_path = (
|
|
|
- f'SELECT count(*) FROM "{table}" c JOIN "{table}" p ON c.parent_id = p.id'
|
|
|
- f' WHERE c.sort_path <> p.sort_path || chr(9) || c.name'
|
|
|
- if sort_path else 'SELECT 0'
|
|
|
+ root_path = (
|
|
|
+ f'SELECT id FROM "{table}"'
|
|
|
+ f" WHERE parent_id IS NULL"
|
|
|
+ f" AND path <> lpad(id::text, {_PATH_LABEL_WIDTH}, '0')::ltree"
|
|
|
+ )
|
|
|
+ child_path = (
|
|
|
+ f'SELECT c.id FROM "{table}" c JOIN "{table}" p ON c.parent_id = p.id'
|
|
|
+ f" WHERE c.path <> p.path || lpad(c.id::text, {_PATH_LABEL_WIDTH}, '0')::ltree"
|
|
|
)
|
|
|
+ if sort_path:
|
|
|
+ root_sort_path = (
|
|
|
+ f'SELECT id FROM "{table}" WHERE parent_id IS NULL AND sort_path <> name'
|
|
|
+ )
|
|
|
+ child_sort_path = (
|
|
|
+ f'SELECT c.id FROM "{table}" c JOIN "{table}" p ON c.parent_id = p.id'
|
|
|
+ f' WHERE c.sort_path <> p.sort_path || chr(9) || c.name'
|
|
|
+ )
|
|
|
+ stale_sort_path = f'SELECT count(*) FROM ({root_sort_path} UNION ALL {child_sort_path}) s'
|
|
|
+ else:
|
|
|
+ stale_sort_path = 'SELECT 0'
|
|
|
+
|
|
|
return f"""
|
|
|
SELECT
|
|
|
- (
|
|
|
- SELECT count(*) FROM "{table}" c JOIN "{table}" p ON c.parent_id = p.id
|
|
|
- WHERE c.path <> p.path || lpad(c.id::text, {_PATH_LABEL_WIDTH}, '0')::ltree
|
|
|
- ) AS stale_paths,
|
|
|
+ (SELECT count(*) FROM ({root_path} UNION ALL {child_path}) p) AS stale_paths,
|
|
|
({stale_sort_path}) AS stale_sort_paths;
|
|
|
"""
|
|
|
|