The AFTER triggers which cascade a hierarchical object's path to its
descendants gated themselves on `OLD.path IS DISTINCT FROM NEW.path`.
`IS DISTINCT FROM` is SQL grammar rather than a schema-qualifiable
operator: it expands to the operand type's `=` operator, resolved from
search_path at CREATE TRIGGER time. The ltree extension installs into
`public`, so a CREATE TRIGGER replayed by pg_restore -- which sets
search_path to the empty string and schema-qualifies every name it can --
could not resolve `ltree = ltree` and failed.
Because psql does not stop on error by default, restoring a v4.7.0 dump
reported success while silently omitting all 11 cascade triggers. Renaming
or moving a group object then left its descendants' path and sort_path
stale, with no error surfaced.
Comparing the paths as text resolves `pg_catalog.text =` instead, which is
always available. The comparison is equivalent because ltree's text I/O is
byte-preserving and ltree_eq is a memcmp over the same bytes.
Also reinstalls the triggers on existing databases, which carry either the
old definition (upgraded in place) or no cascade trigger at all (restored
from a dump), and makes InstallLtreeTriggers idempotent so it can be
re-run. Adds -v ON_ERROR_STOP=1 to the documented restore procedure, which
is what allowed the failure to go unnoticed.