MDEV-22534 Fix self-referencing Item_direct_view_ref
The loop is created in substitute_for_best_equal_field(). It calls Item_ref::transform (for the Item_direct_view_ref object) which calls: Item *new_item= (*ref)->transform(thd, transformer, arg); // TRANSFORM-CALL where transformer is Item::replace_equal_field(). Consider *vr1->ref==field, where vr1 is an Item_direct_view_ref, and field is an Item_field that erroneously participates in a multiple equality. If field->replace_equal_field() returns vr2, another Item_direct_view_ref, with vr2->ref == vr1->ref. vr1->transform() will, after the call on field->transform() that returns vr2 for replacement, update its ref to point to vr2, so now *vr1->ref==vr2, and since vr2->ref==vr1->ref, this gives us *vr2->ref == vr2, a self reference. This can be generalised to nested Item_direct_view_refs too, if field->transform() returns an Item_direct_view_ref that has the same ref field as the ref field of any Item_direct_view_ref in the chain. On to the fix. If we maintain the rule that Objects inside Item_direct_view_ref do not participate in multiple equalities. then the TRANSFORM-CALL will have new_item == *ref. That is, the transform will be a no-op and no loop will be created. The participation of multiple equalities is set during call to Item::propagate_equal_fields(). This commit fixes Item_ref::propagate_equal_fields() so that the rule is not violated when a (non-Item_direct_view_ref) Item_ref points to an Item_direct_view_ref: Item_ref->Item_ref->...->Item_direct_view_ref->Item_direct_view_ref->...->Item_field More specifically, we now delegate to the dereferenced item (i.e. *ref) in such calls, rather than directly to the underlying Item_field. By doing this, the call to propagate_equal_fields() on toplevel Item_direct_view_ref will make it participate in the multiple equality, instead of any of its downstream items.
Showing
Please register or sign in to comment