[17.0][FIX] base: cascade inactive child views on force unlink#9
Open
eantones wants to merge 1 commit into
Open
[17.0][FIX] base: cascade inactive child views on force unlink#9eantones wants to merge 1 commit into
eantones wants to merge 1 commit into
Conversation
View.unlink() emulates an ondelete cascade on inherit_children_ids when _force_unlink is set, but reads that One2many with active_test enabled, so INACTIVE child views are skipped. They still hold the inherit_id RESTRICT foreign key, so the parent's DELETE is rejected, logged as a benign bad query, and the obsolete parent view survives orphaned forever -- _process_end never revisits it and a later -u all does not sweep it. Reproduced upgrading 16.0 -> 17.0: website_sale.payment_footer is dropped from core in 17.0 but survives, because its child payment_sale_note is active="False" and is not cascaded. Read inherit_children_ids with active_test=False so the cascade covers inactive children too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Obsolete parent view is left orphaned when its inherited child view is inactive
Impacted versions:
Description of the issue/feature this PR addresses:
View.unlink()emulates an ondelete cascade overinherit_children_idswhen_force_unlinkis set:inherit_children_idsis a plainOne2many, so it honoursactive_testand inactive child views are never returned. The cascade skips them, but they still hold theinherit_idRESTRICT foreign key, so the parent'sDELETEis rejected. It is logged as a benignbad query, execution continues, and the obsolete parent view is left orphaned.This is not specific to upgrades.
_force_unlinkis set in exactly two places, both ordinary operations:ir.model.data._process_end()sets it while removing records that became obsolete, and is called fromodoo/modules/loading.py("Cleanup orphan records") on every-u/-i;ir.model.data._module_data_uninstall()sets it.A later
-udoes not clean it up either:_process_end()walks its obsolete records once and never revisits the parent, and every subsequent run re-executes the same cascade, skips the same inactive child, and re-fails the sameDELETE.Two conditions must coincide, which is why this is rarely noticed: the parent must be processed before the child (
_process_endorders byir_model_data.id DESC), and the child must be inactive. Either one alone is harmless — an active child is cascaded away, and a child processed first drops the foreign key before the parent's turn.Steps to reproduce:
website_sale.payment_footer(parent) andwebsite_sale.payment_sale_note(child,inherit_id="payment_footer",active="False") are both dropped from core in 17.0.ir_ui_viewforwebsite_sale.payment_footerafter the update.Current behavior before PR:
The parent view stays in
ir_ui_viewpermanently: the cascade did not see the inactive child, the foreign key rejected theDELETE, and nothing retries it.Desired behavior after PR is merged:
The cascade reads the children with
active_test=False, so the inactive child is unlinked before the parent'sDELETE, which then succeeds. No orphan is left behind, and uninstalling a module that owns such a pair removes both views.