Commit b085255
fix(folders): restore new-identifier-on-rename behavior while keeping SQL-based child update (#35176)
## Problem
PR #35086 fixed a critical bug (#34655) where renaming a folder
containing 20K+ contentlets would fail with:
```
ERROR: Cannot delete as this path has children
Where: PL/pgSQL function check_child_assets() line 13 at RAISE
```
The root cause was that the old implementation discovered children via
**Elasticsearch** — any unindexed content was silently skipped, leaving
orphaned DB rows that caused the delete trigger to fire and fail.
PR #35086 fixed this by switching to an **in-place rename** (no
create/delete cycle), which eliminated both the ES dependency and the
delete entirely. However, this introduced an unintended behavioral
change: **the folder identifier (UUID) no longer changes when the folder
URL changes**.
This breaks the contract established by the deterministic identifier
system (`DeterministicIdentifierAPIImpl`), where a folder's UUID is a
SHA-256 hash of `assetType:hostname:parentPath:folderName`. After an
in-place rename, the UUID stays tied to the old path, decoupling
identity from URL.
## Fix
This PR restores the original create-new/delete-old identity contract
while **keeping the SQL-based child discovery** from PR #35086 — the
actual fix for the root cause.
### What changes
**`FolderFactoryImpl.renameFolder()`** — reverts the in-place mutation
back to a create+delete cycle, but replaces the ES-based child discovery
with the depth-first bulk SQL UPDATE:
1. `folder.setName(newName)` so `getNewFolderRecord()` picks up the new
name
2. `getNewFolderRecord()` creates a new folder record — new inode + new
deterministic identifier via `IdentifierAPI.createNew()` (URL change →
identity change restored)
3. `clearIdentifierCacheForSubtree(oldPath)` — evict stale cache entries
before mutation
4. `updateChildPaths(oldPath → newPath)` — depth-first bulk `UPDATE
identifier SET parent_path = ?` sorted by path length, guaranteeing
parent-before-child so the `identifier_parent_path_trigger` passes at
every level without needing deferred constraints
5. Cache evictions (identifier, folder, nav) — unchanged from PR #35086
6. `updateOtherFolderReferences(newInode, oldInode)` — restored from
pre-#35086 code; needed because the inode now changes (permissions,
content-type structure references)
7. `delete(folder)` — safe because all children are moved before this
runs, so `check_child_assets()` finds nothing
8. Mutates `folder.setInode()` + `folder.setIdentifier()` on the
caller's reference so `FolderAPIImpl.refreshContentUnderFolder()`
targets the correct new folder
### Why the delete is now safe
The original bug was caused by ES-based child discovery missing
unindexed items. With `updateChildPaths()`, child discovery is a direct
SQL query against the `identifier` table — no ES dependency, no items
skipped. Every child `parent_path` is updated before `delete()` runs, so
`check_child_assets()` finds zero children and the trigger allows the
delete.
### Why no deferred constraints are needed
Depth-first ordering (sort by ascending path length = parent before
child) ensures that by the time the `identifier_parent_path_trigger`
validates each row's new `parent_path`, the parent folder row was
already updated in the previous iteration. No `DEFERRABLE` constraint
changes required.
### Identifier semantics
| | Old (broken, pre-#35086) | PR #35086 (in-place) | This PR |
|---|---|---|---|
| URL change → new UUID | Yes (via ES, unreliable) | No | Yes (via SQL,
reliable) |
| Child discovery | Elasticsearch | Direct SQL | Direct SQL |
| 20K+ item performance | 20K round-trips | 1 UPDATE/depth level | 1
UPDATE/depth level |
| Constraint violation risk | Yes (unindexed items) | None (no delete) |
None (children moved first) |
## Tests updated
- **`renameFolder()`** — captures old identifier before rename; asserts
old identifier is deleted, sub-folder identifiers are preserved (only
`parent_path` updated), renamed folder has new UUID
- **`renameFolder_updatesChildrenAndSubChildrenPaths()`** — asserts old
parent identifier is deleted, new identifier exists with correct
`asset_name`, sub-folder identifier is unchanged, all `parent_path`
values are correct at every nesting level
Fixes #34655
---------
Co-authored-by: Claude Sonnet 4.6 <[email protected]>1 parent 5fa89df commit b085255
3 files changed
Lines changed: 102 additions & 85 deletions
File tree
- dotCMS/src/main/java/com/dotmarketing/portlets/folders/business
- dotcms-integration/src/test/java/com/dotmarketing/portlets/folders/business
Lines changed: 9 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
174 | 174 | | |
175 | 175 | | |
176 | 176 | | |
177 | | - | |
178 | | - | |
179 | | - | |
180 | | - | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
181 | 182 | | |
182 | 183 | | |
183 | 184 | | |
| |||
676 | 677 | | |
677 | 678 | | |
678 | 679 | | |
679 | | - | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
680 | 684 | | |
681 | 685 | | |
682 | 686 | | |
| |||
Lines changed: 56 additions & 60 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
55 | | - | |
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| |||
632 | 632 | | |
633 | 633 | | |
634 | 634 | | |
635 | | - | |
636 | | - | |
637 | | - | |
638 | | - | |
639 | | - | |
640 | | - | |
641 | | - | |
642 | | - | |
643 | | - | |
644 | | - | |
645 | | - | |
646 | | - | |
647 | | - | |
648 | | - | |
649 | | - | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
650 | 649 | | |
651 | 650 | | |
652 | 651 | | |
| |||
778 | 777 | | |
779 | 778 | | |
780 | 779 | | |
| 780 | + | |
781 | 781 | | |
782 | 782 | | |
783 | 783 | | |
| |||
805 | 805 | | |
806 | 806 | | |
807 | 807 | | |
808 | | - | |
809 | | - | |
810 | | - | |
811 | | - | |
812 | | - | |
813 | | - | |
814 | | - | |
815 | | - | |
816 | | - | |
817 | | - | |
818 | | - | |
819 | | - | |
820 | | - | |
821 | | - | |
822 | | - | |
823 | | - | |
824 | | - | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
825 | 818 | | |
826 | | - | |
827 | | - | |
828 | | - | |
829 | | - | |
830 | | - | |
831 | | - | |
832 | | - | |
833 | | - | |
834 | | - | |
835 | | - | |
836 | | - | |
837 | | - | |
838 | | - | |
839 | | - | |
| 819 | + | |
840 | 820 | | |
841 | | - | |
842 | | - | |
| 821 | + | |
843 | 822 | | |
844 | 823 | | |
845 | 824 | | |
| |||
849 | 828 | | |
850 | 829 | | |
851 | 830 | | |
852 | | - | |
853 | | - | |
854 | | - | |
855 | | - | |
856 | | - | |
| 831 | + | |
| 832 | + | |
857 | 833 | | |
858 | 834 | | |
859 | 835 | | |
860 | | - | |
| 836 | + | |
| 837 | + | |
861 | 838 | | |
862 | 839 | | |
863 | | - | |
864 | | - | |
865 | | - | |
| 840 | + | |
866 | 841 | | |
867 | 842 | | |
868 | | - | |
| 843 | + | |
869 | 844 | | |
870 | 845 | | |
871 | | - | |
| 846 | + | |
| 847 | + | |
872 | 848 | | |
873 | 849 | | |
874 | 850 | | |
875 | 851 | | |
876 | 852 | | |
877 | 853 | | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
878 | 874 | | |
879 | 875 | | |
880 | 876 | | |
| |||
Lines changed: 37 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
154 | | - | |
| 154 | + | |
155 | 155 | | |
156 | | - | |
157 | | - | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
158 | 159 | | |
159 | 160 | | |
160 | 161 | | |
| |||
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
170 | 174 | | |
171 | 175 | | |
172 | 176 | | |
173 | | - | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
174 | 185 | | |
175 | 186 | | |
176 | 187 | | |
177 | | - | |
178 | | - | |
179 | 188 | | |
180 | 189 | | |
181 | 190 | | |
182 | 191 | | |
183 | | - | |
184 | | - | |
185 | 192 | | |
186 | 193 | | |
187 | 194 | | |
188 | 195 | | |
189 | 196 | | |
| 197 | + | |
190 | 198 | | |
191 | 199 | | |
192 | 200 | | |
| |||
196 | 204 | | |
197 | 205 | | |
198 | 206 | | |
| 207 | + | |
199 | 208 | | |
| 209 | + | |
| 210 | + | |
200 | 211 | | |
201 | 212 | | |
202 | 213 | | |
| |||
239 | 250 | | |
240 | 251 | | |
241 | 252 | | |
242 | | - | |
| 253 | + | |
| 254 | + | |
243 | 255 | | |
244 | 256 | | |
245 | 257 | | |
| |||
268 | 280 | | |
269 | 281 | | |
270 | 282 | | |
| 283 | + | |
271 | 284 | | |
272 | 285 | | |
273 | 286 | | |
| |||
277 | 290 | | |
278 | 291 | | |
279 | 292 | | |
280 | | - | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
285 | | - | |
286 | | - | |
287 | | - | |
288 | | - | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
289 | 304 | | |
290 | 305 | | |
291 | 306 | | |
| |||
311 | 326 | | |
312 | 327 | | |
313 | 328 | | |
314 | | - | |
| 329 | + | |
315 | 330 | | |
316 | 331 | | |
317 | | - | |
| 332 | + | |
318 | 333 | | |
| 334 | + | |
| 335 | + | |
319 | 336 | | |
320 | 337 | | |
321 | 338 | | |
| |||
0 commit comments