Thread: Constraint merge and not valid status

Constraint merge and not valid status

From
Amit Langote
Date:
Hi,

Consider a scenario where one adds a *valid* constraint on a inheritance
parent which is then merged with a child table's *not valid* constraint
during inheritance recursion.  If merged, the constraint is not checked
for the child data even though it may have some.  Is that an oversight?

Thanks,
Amit





Re: Constraint merge and not valid status

From
Jim Nasby
Date:
On 7/13/16 4:22 AM, Amit Langote wrote:
> Consider a scenario where one adds a *valid* constraint on a inheritance
> parent which is then merged with a child table's *not valid* constraint
> during inheritance recursion.  If merged, the constraint is not checked
> for the child data even though it may have some.  Is that an oversight?

Seen as how you used to be able to illegally twerk NOT NULL status on 
children (and maybe still can), I'd bet this is a bug...
-- 
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
855-TREBLE2 (855-873-2532)   mobile: 512-569-9461



Re: Constraint merge and not valid status

From
Robert Haas
Date:
On Wed, Jul 13, 2016 at 5:22 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Consider a scenario where one adds a *valid* constraint on a inheritance
> parent which is then merged with a child table's *not valid* constraint
> during inheritance recursion.  If merged, the constraint is not checked
> for the child data even though it may have some.  Is that an oversight?

Seems like it.  I'd recommend we just error out in that case and tell
the user that they should validate the child's constraint first.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Constraint merge and not valid status

From
Amit Langote
Date:
On 2016/07/22 0:38, Robert Haas wrote:
> On Wed, Jul 13, 2016 at 5:22 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Consider a scenario where one adds a *valid* constraint on a inheritance
>> parent which is then merged with a child table's *not valid* constraint
>> during inheritance recursion.  If merged, the constraint is not checked
>> for the child data even though it may have some.  Is that an oversight?
>
> Seems like it.  I'd recommend we just error out in that case and tell
> the user that they should validate the child's constraint first.

Agreed.

Patch attached.  In addition to the recursion from parent case, this seems
to be broken for the alter table child inherit parent case as well. So,
fixed both MergeWithExistingConstraint (called from
AddRelationNewConstraints) and MergeConstraintsIntoExisting (called from
ATExecAddInherit). I had to add a new argument is_not_valid to the former
to signal whether the constraint being propagated itself is declared NOT
VALID, in which we can proceed with merging.  Also added some tests for
both cases.

Thanks,
Amit

Attachment

Re: Constraint merge and not valid status

From
Kyotaro HORIGUCHI
Date:
Hello,

At Fri, 22 Jul 2016 14:10:48 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in
<b5e5d627-2fee-46f5-c219-9915416a9196@lab.ntt.co.jp>
> On 2016/07/22 0:38, Robert Haas wrote:
> > On Wed, Jul 13, 2016 at 5:22 AM, Amit Langote
> > <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> >> Consider a scenario where one adds a *valid* constraint on a inheritance
> >> parent which is then merged with a child table's *not valid* constraint
> >> during inheritance recursion.  If merged, the constraint is not checked
> >> for the child data even though it may have some.  Is that an oversight?
> > 
> > Seems like it.  I'd recommend we just error out in that case and tell
> > the user that they should validate the child's constraint first.
> 
> Agreed.
> 
> Patch attached.  In addition to the recursion from parent case, this seems
> to be broken for the alter table child inherit parent case as well. So,
> fixed both MergeWithExistingConstraint (called from
> AddRelationNewConstraints) and MergeConstraintsIntoExisting (called from
> ATExecAddInherit). I had to add a new argument is_not_valid to the former
> to signal whether the constraint being propagated itself is declared NOT
> VALID, in which we can proceed with merging.  Also added some tests for
> both cases.

It seems to work as expected and message seems to be
reasonable. Test seems to be fine.

By the way I have one question.

Is it an expected configuration where tables in an inheritance
tree has different valid state on the same (check) constraint?
The check should be an equality if it's not.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center





Re: Constraint merge and not valid status

From
Amit Langote
Date:
Hello,

On 2016/07/22 17:06, Kyotaro HORIGUCHI wrote:
> At Fri, 22 Jul 2016 14:10:48 +0900, Amit Langote wrote:
>> On 2016/07/22 0:38, Robert Haas wrote:
>>> On Wed, Jul 13, 2016 at 5:22 AM, Amit Langote wrote:
>>>> Consider a scenario where one adds a *valid* constraint on a inheritance
>>>> parent which is then merged with a child table's *not valid* constraint
>>>> during inheritance recursion.  If merged, the constraint is not checked
>>>> for the child data even though it may have some.  Is that an oversight?
>>>
>>> Seems like it.  I'd recommend we just error out in that case and tell
>>> the user that they should validate the child's constraint first.
>>
>> Agreed.
>>
>> Patch attached.  In addition to the recursion from parent case, this seems
>> to be broken for the alter table child inherit parent case as well. So,
>> fixed both MergeWithExistingConstraint (called from
>> AddRelationNewConstraints) and MergeConstraintsIntoExisting (called from
>> ATExecAddInherit). I had to add a new argument is_not_valid to the former
>> to signal whether the constraint being propagated itself is declared NOT
>> VALID, in which we can proceed with merging.  Also added some tests for
>> both cases.
> 
> It seems to work as expected and message seems to be
> reasonable. Test seems to be fine.

Thanks for reviewing.

> By the way I have one question.
> 
> Is it an expected configuration where tables in an inheritance
> tree has different valid state on the same (check) constraint?

I would think not.

> The check should be an equality if it's not.

If you mean that the valid state should be same (equal) at all times on
parent and all the child tables, then that is exactly what the patch tries
to achieve.  Currently, valid state of a constraint on a child table is
left to differ from the parent in two cases as described in my messages.

Thanks,
Amit





Re: Constraint merge and not valid status

From
Kyotaro HORIGUCHI
Date:
Hello,

At Fri, 22 Jul 2016 17:35:48 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in
<9733fae3-c32f-b150-e368-a8f87d546a7f@lab.ntt.co.jp>
> On 2016/07/22 17:06, Kyotaro HORIGUCHI wrote:
> > At Fri, 22 Jul 2016 14:10:48 +0900, Amit Langote wrote:
> >> On 2016/07/22 0:38, Robert Haas wrote:
> >>> On Wed, Jul 13, 2016 at 5:22 AM, Amit Langote wrote:
> >>>> Consider a scenario where one adds a *valid* constraint on a inheritance
> >>>> parent which is then merged with a child table's *not valid* constraint
> >>>> during inheritance recursion.  If merged, the constraint is not checked
> >>>> for the child data even though it may have some.  Is that an oversight?
> >>>
> >>> Seems like it.  I'd recommend we just error out in that case and tell
> >>> the user that they should validate the child's constraint first.
> >>
> >> Agreed.
> >>
> >> Patch attached.  In addition to the recursion from parent case, this seems
> >> to be broken for the alter table child inherit parent case as well. So,
> >> fixed both MergeWithExistingConstraint (called from
> >> AddRelationNewConstraints) and MergeConstraintsIntoExisting (called from
> >> ATExecAddInherit). I had to add a new argument is_not_valid to the former
> >> to signal whether the constraint being propagated itself is declared NOT
> >> VALID, in which we can proceed with merging.  Also added some tests for
> >> both cases.
> > 
> > It seems to work as expected and message seems to be
> > reasonable. Test seems to be fine.
> 
> Thanks for reviewing.
> 
> > By the way I have one question.
> > 
> > Is it an expected configuration where tables in an inheritance
> > tree has different valid state on the same (check) constraint?
> 
> I would think not.

I understand that the first problem is that the problematic
state inhibits later VALIDATE CONSTRAINT on parent from working
as expected.  This patch inhibits the state where a parent is
valid and any of its children is not-valid, but allows the
opposite and it is enough to fix the problem.

I thought the opposite state is ok generally but not with full
confidence.

After some reading the code, it seems to affect only on some
cache invalidation logics and constraint exclusion logic to
ignore the check constraint per component table, and
acquire_inherited_sample_rows.

The first and second wouldn't harm. The third causes needless
tuple conversion. If this is a problem, the validity state of all
relations in an inheritance tree should be exactly the same,
ether valid or not-valid. Or should make the function to ignore
the difference of validity state.

If the problem is only VALIDATE CONSTRAINT on the parent and
mixted validity states within an inheritance tree is not, making
it process whole the inheritance tree regardsless of the validity
state of the parent would also fix the problem.

After all, my concerns are the following.
- Is the mixed validity states (in any form) in an inheritnce  tree should be valid? If so, VALIDATE CONSTRAINT should
be fixed, not MergeWithExistingConstraint. If not, the opposite  state also should be inhibited.
 
- Is it valid to represent all descendants' validity states by  the parent's state? (Currently only VALIDATE CONSTRAINT
does) If not, VALIDATE CONSTRAINT should be fixed.
 

Any thoughts?


> > The check should be an equality if it's not.
> 
> If you mean that the valid state should be same (equal) at all times on
> parent and all the child tables, then that is exactly what the patch tries
> to achieve.  Currently, valid state of a constraint on a child table is
> left to differ from the parent in two cases as described in my messages.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center





Re: Constraint merge and not valid status

From
Amit Langote
Date:
Hello,

On 2016/07/25 12:44, Kyotaro HORIGUCHI wrote:
> At Fri, 22 Jul 2016 17:35:48 +0900, Amit Langote wrote:
>> On 2016/07/22 17:06, Kyotaro HORIGUCHI wrote:
>>
>>> By the way I have one question.
>>>
>>> Is it an expected configuration where tables in an inheritance
>>> tree has different valid state on the same (check) constraint?
>>
>> I would think not.
> 
> I understand that the first problem is that the problematic
> state inhibits later VALIDATE CONSTRAINT on parent from working
> as expected.  This patch inhibits the state where a parent is
> valid and any of its children is not-valid, but allows the
> opposite and it is enough to fix the problem.
> 
> I thought the opposite state is ok generally but not with full
> confidence.

I obviously missed the opposite case.  However, it's OK for a child's
constraint to be valid while the parent's is not.  There seems to be in
place only the one-way rule which is that we don't mark parent's
constraint valid until and unless it is marked valid on all the child
tables.  From the following comment in ATExecValidateConstraint():

/** For CHECK constraints, we must ensure that we only mark the* constraint as validated on the parent if it's already
validated*on the children.*
 

And it seems to be in place only for VALIDATE CONSTRAINT's purpose.

> After some reading the code, it seems to affect only on some
> cache invalidation logics and constraint exclusion logic to
> ignore the check constraint per component table, and
> acquire_inherited_sample_rows.
>
> The first and second wouldn't harm. The third causes needless
> tuple conversion. If this is a problem, the validity state of all
> relations in an inheritance tree should be exactly the same,
> ether valid or not-valid. Or should make the function to ignore
> the difference of validity state.

Hmm, perhaps check constraint valid status affecting whether
child-to-parent-rowtype conversion should occur is unnecessary.  Maybe a
subset of those checks for purposes of acquire_inherited_sample_rows would
suffice.  Or simply make equalTupleDescs accept a boolean parameter that
indicates whether or not to check TupleConstr equality.

> If the problem is only VALIDATE CONSTRAINT on the parent and
> mixted validity states within an inheritance tree is not, making
> it process whole the inheritance tree regardsless of the validity
> state of the parent would also fix the problem.
> 
> After all, my concerns are the following.
> 
>  - Is the mixed validity states (in any form) in an inheritnce
>    tree should be valid? If so, VALIDATE CONSTRAINT should be
>    fixed, not MergeWithExistingConstraint. If not, the opposite
>    state also should be inhibited.
> 
>  - Is it valid to represent all descendants' validity states by
>    the parent's state? (Currently only VALIDATE CONSTRAINT does)
>    If not, VALIDATE CONSTRAINT should be fixed.
> 
> Any thoughts?

Wouldn't it be better to leave VALIDATE CONSTRAINT alone, because the way
it works now it short-circuits some extra processing if the parent's
constraint is marked valid?  All we need to do is to prevent the rule from
being broken by fixing the current code like the patch proposes.  If we
try to fix the VALIDATE CONSTRAINT instead, we'll always have to pay the
cost of find_all_inheritors().  Thoughts?

As for the other cases (determining whether we can live with the state
where a child's constraint is valid whereas the same on the parent and
siblings is not):

1. Both cache invalidation and acquire_inherited_sample_rows depend on
equalTupleDescs, where the former is unrelated to inheritance behavior as
such (and hence unaffected by current discussion); for the latter, we
might want to simply ignore comparing the check constraint valid status as
mentioned above

2. Constraint exclusion, where it seems OK for a child's check constraint
to cause it to be excluded while the same check constraint of its parent
and siblings is ignored causing them to be needlessly scanned.

Thanks,
Amit





Re: Constraint merge and not valid status

From
Kyotaro HORIGUCHI
Date:
Hello,

At Mon, 25 Jul 2016 15:57:00 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in
<fe27dd92-61bb-eb63-da47-63b535e41c48@lab.ntt.co.jp>
> On 2016/07/25 12:44, Kyotaro HORIGUCHI wrote:
> > At Fri, 22 Jul 2016 17:35:48 +0900, Amit Langote wrote:
> >> On 2016/07/22 17:06, Kyotaro HORIGUCHI wrote:
> >>
> >>> By the way I have one question.
> >>>
> >>> Is it an expected configuration where tables in an inheritance
> >>> tree has different valid state on the same (check) constraint?
> >>
> >> I would think not.
> > 
> > I understand that the first problem is that the problematic
> > state inhibits later VALIDATE CONSTRAINT on parent from working
> > as expected.  This patch inhibits the state where a parent is
> > valid and any of its children is not-valid, but allows the
> > opposite and it is enough to fix the problem.
> > 
> > I thought the opposite state is ok generally but not with full
> > confidence.
> 
> I obviously missed the opposite case.  However, it's OK for a child's
> constraint to be valid while the parent's is not.  There seems to be in
> place only the one-way rule which is that we don't mark parent's
> constraint valid until and unless it is marked valid on all the child
> tables.  From the following comment in ATExecValidateConstraint():
> 
> /*
>  * For CHECK constraints, we must ensure that we only mark the
>  * constraint as validated on the parent if it's already validated
>  * on the children.
>  *
> 
> And it seems to be in place only for VALIDATE CONSTRAINT's purpose.

Agreed. It guarantees nothing outside the function but it shows
that at least one side of mixed validity status is/should be
considered.

> > After some reading the code, it seems to affect only on some
> > cache invalidation logics and constraint exclusion logic to
> > ignore the check constraint per component table, and
> > acquire_inherited_sample_rows.
> >
> > The first and second wouldn't harm. The third causes needless
> > tuple conversion. If this is a problem, the validity state of all
> > relations in an inheritance tree should be exactly the same,
> > ether valid or not-valid. Or should make the function to ignore
> > the difference of validity state.
> 
> Hmm, perhaps check constraint valid status affecting whether
> child-to-parent-rowtype conversion should occur is unnecessary.  Maybe a
> subset of those checks for purposes of acquire_inherited_sample_rows would
> suffice.  Or simply make equalTupleDescs accept a boolean parameter that
> indicates whether or not to check TupleConstr equality.

equalTupleDescs are used in few places. The equalTupleDescs's
"Logical" equality seems to stem from the compatibility while
given to heap_form/modify_tuple. I don't think the validity
status has something to do with the result of such functions.

> > If the problem is only VALIDATE CONSTRAINT on the parent and
> > mixted validity states within an inheritance tree is not, making
> > it process whole the inheritance tree regardsless of the validity
> > state of the parent would also fix the problem.
> > 
> > After all, my concerns are the following.
> > 
> >  - Is the mixed validity states (in any form) in an inheritnce
> >    tree should be valid? If so, VALIDATE CONSTRAINT should be
> >    fixed, not MergeWithExistingConstraint. If not, the opposite
> >    state also should be inhibited.
> > 
> >  - Is it valid to represent all descendants' validity states by
> >    the parent's state? (Currently only VALIDATE CONSTRAINT does)
> >    If not, VALIDATE CONSTRAINT should be fixed.
> > 
> > Any thoughts?
> 
> Wouldn't it be better to leave VALIDATE CONSTRAINT alone, because the way
> it works now it short-circuits some extra processing if the parent's
> constraint is marked valid?  All we need to do is to prevent the rule from
> being broken by fixing the current code like the patch proposes.  If we
> try to fix the VALIDATE CONSTRAINT instead, we'll always have to pay the
> cost of find_all_inheritors().  Thoughts?

VALIDATE CONSTRAINT is expected to take a long time like analyze
and used for very limited cases so the cost of
find_all_inheritors() don't seem to be siginificant. However,
such modification would give a pain more than required. As the
result, I agree with you.

> As for the other cases (determining whether we can live with the state
> where a child's constraint is valid whereas the same on the parent and
> siblings is not):
> 
> 1. Both cache invalidation and acquire_inherited_sample_rows depend on
> equalTupleDescs, where the former is unrelated to inheritance behavior as
> such (and hence unaffected by current discussion); for the latter, we
> might want to simply ignore comparing the check constraint valid status as
> mentioned above
> 
> 2. Constraint exclusion, where it seems OK for a child's check constraint
> to cause it to be excluded while the same check constraint of its parent
> and siblings is ignored causing them to be needlessly scanned.

Agreed to the both. So the conclusion here is,
- Inhibit only the case where parent is to be validated while  child is not-validated while merge. The oppsite is
deliberatelyallowed and properly handled by VALIDATE  CONSTRAINT.
 
  That is, the last patch doesn't need modification.
- Remove ccvalid condition from equalTupleDescs() to reduce  unnecessary cache invalidation or tuple rebuilding.
  The attached patch does this.


These two thing seems to be different problem.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center

Re: Constraint merge and not valid status

From
Amit Langote
Date:
Hello,

On 2016/07/25 17:18, Kyotaro HORIGUCHI wrote:
>
>  - Remove ccvalid condition from equalTupleDescs() to reduce
>    unnecessary cache invalidation or tuple rebuilding.

The following commit introduced the ccvalid check:

"""
commit c31305de5f5a4880b0ba2f5983025ef0210a3b2a
Author: Noah Misch <noah@leadboat.com>
Date:   Sun Mar 23 02:13:43 2014 -0400

Address ccvalid/ccnoinherit in TupleDesc support functions.

equalTupleDescs() neglected both of these ConstrCheck fields, and
CreateTupleDescCopyConstr() neglected ccnoinherit.  At this time, the
only known behavior defect resulting from these omissions is constraint
exclusion disregarding a CHECK constraint validated by an ALTER TABLE
VALIDATE CONSTRAINT statement issued earlier in the same transaction.
Back-patch to 9.2, where these fields were introduced.
"""

So, apparently RelationClearRelation() does intend to discard a cached
TupleDesc if ccvalid changed in a transaction.  Whereas,
acquire_inherited_sample_rows() does not seem to depend on ccvalid being
equal or not (or any member of TupleConstr for that matter).  So maybe,
instead of simply discarding the check (which does serve a purpose), we
could make equalTupleDescs() parameterized on whether we want TupleConstr
equality check to be performed or not.  RelationClearRelation() can ask
for the check to be performed by passing true for the parameter whereas
acquire_inherited_sample_rows() and other callers can pass false.  Perhaps
something like the attached.

Thanks,
Amit

Attachment

Re: Constraint merge and not valid status

From
Kyotaro HORIGUCHI
Date:
Hello,

At Mon, 25 Jul 2016 18:21:27 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in
<96fb8bca-57f5-e5a8-9630-79d4fc5b213e@lab.ntt.co.jp>
> 
> Hello,
> 
> On 2016/07/25 17:18, Kyotaro HORIGUCHI wrote:
> > 
> >  - Remove ccvalid condition from equalTupleDescs() to reduce
> >    unnecessary cache invalidation or tuple rebuilding.
> 
> The following commit introduced the ccvalid check:
> 
> """
> commit c31305de5f5a4880b0ba2f5983025ef0210a3b2a
> Author: Noah Misch <noah@leadboat.com>
> Date:   Sun Mar 23 02:13:43 2014 -0400
> 
> Address ccvalid/ccnoinherit in TupleDesc support functions.
> 
> equalTupleDescs() neglected both of these ConstrCheck fields, and
> CreateTupleDescCopyConstr() neglected ccnoinherit.  At this time, the
> only known behavior defect resulting from these omissions is constraint
> exclusion disregarding a CHECK constraint validated by an ALTER TABLE
> VALIDATE CONSTRAINT statement issued earlier in the same transaction.
> Back-patch to 9.2, where these fields were introduced.
> """

Wow.. Missed the obvious thing. Certainly relation cache must be
invalidated by a change of ccvalidated as the commit message.

> So, apparently RelationClearRelation() does intend to discard a cached
> TupleDesc if ccvalid changed in a transaction.  Whereas,
> acquire_inherited_sample_rows() does not seem to depend on ccvalid being
> equal or not (or any member of TupleConstr for that matter).  So maybe,
> instead of simply discarding the check (which does serve a purpose), we
> could make equalTupleDescs() parameterized on whether we want TupleConstr
> equality check to be performed or not.  RelationClearRelation() can ask
> for the check to be performed by passing true for the parameter whereas
> acquire_inherited_sample_rows() and other callers can pass false.  Perhaps
> something like the attached.

Hmm. It should resolve the problem. But the two comparisons seem
to be separate things. Constraints is not a part of tuple
description. relcache seems to be making misusage of the equality
of tuple descriptors.

So, how about splitting the original equalTupleDescs into
equalTupleDescs and equalTupleConstraints ?

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center

Re: Constraint merge and not valid status

From
Amit Langote
Date:
Hello,

On 2016/07/26 11:05, Kyotaro HORIGUCHI wrote:
> At Mon, 25 Jul 2016 18:21:27 +0900, Amit Langote wrote:
> 
>> So, apparently RelationClearRelation() does intend to discard a cached
>> TupleDesc if ccvalid changed in a transaction.  Whereas,
>> acquire_inherited_sample_rows() does not seem to depend on ccvalid being
>> equal or not (or any member of TupleConstr for that matter).  So maybe,
>> instead of simply discarding the check (which does serve a purpose), we
>> could make equalTupleDescs() parameterized on whether we want TupleConstr
>> equality check to be performed or not.  RelationClearRelation() can ask
>> for the check to be performed by passing true for the parameter whereas
>> acquire_inherited_sample_rows() and other callers can pass false.  Perhaps
>> something like the attached.
> 
> Hmm. It should resolve the problem. But the two comparisons seem
> to be separate things. Constraints is not a part of tuple
> description. relcache seems to be making misusage of the equality
> of tuple descriptors.
> 
> So, how about splitting the original equalTupleDescs into
> equalTupleDescs and equalTupleConstraints ?

Actually TupleConstr is *part* of the TupleDesc struct, which the
relcache.c tries to preserve in *whole* across a relcache flush, so it
seems perhaps cleaner to keep the decision centralized in one function:
 keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att); ... /* preserve old tupledesc and rules if no
logicalchange */ if (keep_tupdesc)     SWAPFIELD(TupleDesc, rd_att);
 

Also:
 /*  * This struct is passed around within the backend to describe the  * structure of tuples.  For tuples coming from
on-diskrelations, the  * information is collected from the pg_attribute, pg_attrdef, and  * pg_constraint catalogs.
...typedef struct tupleDesc {
 

It would perhaps have been clear if there was a rd_constr field that
relcache.c independently managed.

OTOH, I tend to agree that other places don't quite need the whole thing
(given also that most other callers except acquire_inherit_sample_rows
compare transient row types)

Thanks,
Amit





Re: Constraint merge and not valid status

From
Kyotaro HORIGUCHI
Date:
At Tue, 26 Jul 2016 13:51:53 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in
<f8f2a32e-46da-d34d-cabc-24e75d6da082@lab.ntt.co.jp>
> > So, how about splitting the original equalTupleDescs into
> > equalTupleDescs and equalTupleConstraints ?
> 
> Actually TupleConstr is *part* of the TupleDesc struct, which the
> relcache.c tries to preserve in *whole* across a relcache flush, so it
> seems perhaps cleaner to keep the decision centralized in one function:

The "Logical" is the cause of the ambiguity. It could be thought
that relation cache maintains "Physical" tuple descriptor, which
is defferent from "Logical" one.

>   keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
>   ...
>   /* preserve old tupledesc and rules if no logical change */
>   if (keep_tupdesc)
>       SWAPFIELD(TupleDesc, rd_att);
> 
> Also:
> 
>   /*
>    * This struct is passed around within the backend to describe the
>    * structure of tuples.  For tuples coming from on-disk relations, the
>    * information is collected from the pg_attribute, pg_attrdef, and
>    * pg_constraint catalogs.
>    ...
>   typedef struct tupleDesc
>   {
> 
> It would perhaps have been clear if there was a rd_constr field that
> relcache.c independently managed.
> 
> OTOH, I tend to agree that other places don't quite need the whole thing
> (given also that most other callers except acquire_inherit_sample_rows
> compare transient row types)

Yes, constraints apparently doesn't affect the shpae of
generatred tuples. On the other hand relcache should be aware of
changes of constraints. Furthermore the transient row types has
utterly no relation with constraints of even underlying
relations.

So, almost as your proposition, what do you think if the
equalTupleDescs has extra parameter but named "logical", and
ignore constraints if it is true? (Obviously the opposite will
do). What I felt uneasy about is the name "compare_constr".

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center





Re: Constraint merge and not valid status

From
Robert Haas
Date:
On Fri, Jul 22, 2016 at 1:10 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2016/07/22 0:38, Robert Haas wrote:
>> On Wed, Jul 13, 2016 at 5:22 AM, Amit Langote
>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> Consider a scenario where one adds a *valid* constraint on a inheritance
>>> parent which is then merged with a child table's *not valid* constraint
>>> during inheritance recursion.  If merged, the constraint is not checked
>>> for the child data even though it may have some.  Is that an oversight?
>>
>> Seems like it.  I'd recommend we just error out in that case and tell
>> the user that they should validate the child's constraint first.
>
> Agreed.
>
> Patch attached.  In addition to the recursion from parent case, this seems
> to be broken for the alter table child inherit parent case as well. So,
> fixed both MergeWithExistingConstraint (called from
> AddRelationNewConstraints) and MergeConstraintsIntoExisting (called from
> ATExecAddInherit). I had to add a new argument is_not_valid to the former
> to signal whether the constraint being propagated itself is declared NOT
> VALID, in which we can proceed with merging.  Also added some tests for
> both cases.

Well, on second thought, I'm no longer sure that this approach makes
sense.  I mean, it's obviously wrong for constraint-merging to change
the validity marking on a constraint, but that does not necessarily
imply that we shouldn't merge the constraints, does it?  I see the
downthread discussion saying that it's a problem if the parent's
constraint is marked valid while the child's constraint isn't, but I
don't quite understand why that situation would cause trouble.  In
other words, I see that the current situation is not good, but I'm not
sure I understand what's going on here well enough to be confident
that any of the proposed fixes are correct.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Constraint merge and not valid status

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> Well, on second thought, I'm no longer sure that this approach makes
> sense.  I mean, it's obviously wrong for constraint-merging to change
> the validity marking on a constraint, but that does not necessarily
> imply that we shouldn't merge the constraints, does it?  I see the
> downthread discussion saying that it's a problem if the parent's
> constraint is marked valid while the child's constraint isn't, but I
> don't quite understand why that situation would cause trouble.  In
> other words, I see that the current situation is not good, but I'm not
> sure I understand what's going on here well enough to be confident
> that any of the proposed fixes are correct.

The point I think is that a valid CHECK constraint on a parent table
should imply that all rows fetched by "SELECT * FROM table" will pass
the check.  Therefore, a situation with valid parent constraint and
not-valid child constraint is bad because it might allow some rows
fetched by an inheritance scan to not pass the check.  Quite aside from
any user-level expectations, this could break planner optimizations.

I'd be satisfied with the upthread proposal "throw error if the child has
a matching not-valid constraint".  Allowing the merge if both child
and new parent constraint are not-valid is all right as an extension,
but it seems like a feature with a mighty narrow use case, and I would
not go far out of our way to support it.  Causing the command to not
merge but instead create a new duplicate child constraint seems like a
seriously bad idea (though I'm not sure that anyone was advocating for
that).
        regards, tom lane