Обсуждение: BUG #15623: Inconsistent use of default for updatable view

Поиск
Список
Период
Сортировка

BUG #15623: Inconsistent use of default for updatable view

От
PG Bug reporting form
Дата:
The following bug has been logged on the website:

Bug reference:      15623
Logged by:          Roger Curley
Email address:      rocurley@gmail.com
PostgreSQL version: 11.1
Operating system:   Ubuntu 11.1
Description:

Steps to reproduce (run in psql shell):
```
DROP TABLE IF EXISTS test CASCADE;
CREATE TABLE test (
  id int PRIMARY KEY,
  value int DEFAULT 0
);
CREATE VIEW test_view AS (SELECT * FROM test);

INSERT INTO test_view VALUES (1, DEFAULT), (2, DEFAULT);
INSERT INTO test VALUES (3, DEFAULT), (4, DEFAULT);
INSERT INTO test_view VALUES (5, DEFAULT);
SELECT * FROM test;
```

Result:
```
 id | value 
----+-------
  1 |      
  2 |      
  3 |     0
  4 |     0
  5 |     0
```

Expected Result:
```
 id | value 
----+-------
  1 |     0
  2 |     0
  3 |     0
  4 |     0
  5 |     0
```
In particular, it's surprising that inserting 1 row into an updatable view
uses the table default, while inserting 2 uses null.


Re: BUG #15623: Inconsistent use of default for updatable view

От
Amit Langote
Дата:
Hi,

On 2019/02/08 6:42, PG Bug reporting form wrote:
> The following bug has been logged on the website:
> 
> Bug reference:      15623
> Logged by:          Roger Curley
> Email address:      rocurley@gmail.com
> PostgreSQL version: 11.1
> Operating system:   Ubuntu 11.1
> Description:        
> 
> Steps to reproduce (run in psql shell):
> ```
> DROP TABLE IF EXISTS test CASCADE;
> CREATE TABLE test (
>   id int PRIMARY KEY,
>   value int DEFAULT 0
> );
> CREATE VIEW test_view AS (SELECT * FROM test);
> 
> INSERT INTO test_view VALUES (1, DEFAULT), (2, DEFAULT);
> INSERT INTO test VALUES (3, DEFAULT), (4, DEFAULT);
> INSERT INTO test_view VALUES (5, DEFAULT);
> SELECT * FROM test;
> ```
> 
> Result:
> ```
>  id | value 
> ----+-------
>   1 |      
>   2 |      
>   3 |     0
>   4 |     0
>   5 |     0
> ```
> 
> Expected Result:
> ```
>  id | value 
> ----+-------
>   1 |     0
>   2 |     0
>   3 |     0
>   4 |     0
>   5 |     0
> ```
> In particular, it's surprising that inserting 1 row into an updatable view
> uses the table default, while inserting 2 uses null.

Thanks for the report.  Seems odd indeed.

Looking into this, the reason it works when inserting just one row vs.
more than one row is that those two cases are handled by nearby but
different pieces of code.  The code that handles multiple rows seems buggy
as seen in the above example.  Specifically, I think the bug is in
rewriteValuesRTE() which is a function to replace the default placeholders
in the input rows by the default values as defined for the target
relation.  It is called twice when inserting via the view -- first for the
view relation and then again for the underlying table.  This arrangement
seems to work correctly if the view specifies its own defaults for columns
(assuming that it's okay for the view's defaults to override the
underlying base table's).  If there are no view-specified defaults, then
rewriteValuesRTE replaces the default placeholders in the input row by
NULL constants when called for the first time with the view as target
relation and the next invocation for the underlying table finds that it
has no work to do, so its defaults are not filled.

Attached find a patch that adjusts rewriteValuesRTE to not replace the
default placeholder if the view has no default value for a given column.
Also, adds a test in updatable_views.sql.

Thanks,
Amit

Вложения

Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Fri, 8 Feb 2019 at 05:07, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks for the report.  Seems odd indeed.

Hmm, indeed. That seems to have been broken ever since updatable views
were added.

> Looking into this, the reason it works when inserting just one row vs.
> more than one row is that those two cases are handled by nearby but
> different pieces of code.  The code that handles multiple rows seems buggy
> as seen in the above example.  Specifically, I think the bug is in
> rewriteValuesRTE() which is a function to replace the default placeholders
> in the input rows by the default values as defined for the target
> relation.  It is called twice when inserting via the view -- first for the
> view relation and then again for the underlying table.

Right, except when the view is trigger-updatable. In that case, we do
have to explicitly set the column value to NULL when
rewriteValuesRTE() is called for the view, because it won't be called
again for the underlying table -- it is the trigger's responsibility
to work how (or indeed if) to update the underlying table. IOW, you
need to also use view_has_instead_trigger() to check the view,
otherwise your patch breaks this case:

DROP TABLE IF EXISTS test CASCADE;
CREATE TABLE test (
  id int PRIMARY KEY,
  value int DEFAULT 0
);
CREATE VIEW test_view AS (SELECT * FROM test);

CREATE OR REPLACE FUNCTION test_view_ins() RETURNS trigger
AS
$$
BEGIN
  INSERT INTO test VALUES (NEW.id, NEW.value);
  RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER test_view_trig INSTEAD OF INSERT ON test_view
  FOR EACH ROW EXECUTE FUNCTION test_view_ins();

INSERT INTO test_view VALUES (1, DEFAULT), (2, DEFAULT);

ERROR:  unrecognized node type: 142


While playing around with this, I noticed a related bug affecting the
new identity columns feature. I've not investigated it fully, but It
looks almost the same -- if the column is an identity column, and
we're inserting a multi-row VALUES set containing DEFAULTS, they will
get rewritten to NULLs which will then lead to an error if overriding
the generated value isn't allowed:

DROP TABLE IF EXISTS foo CASCADE;
CREATE TABLE foo
(
  a int,
  b int GENERATED ALWAYS AS IDENTITY
);

INSERT INTO foo VALUES (1,DEFAULT); -- OK
INSERT INTO foo VALUES (2,DEFAULT),(3,DEFAULT); -- Fails

I think fixing that should be tackled separately, because it may turn
out to be subtly different, but it definitely looks like another bug.

Regards,
Dean


Re: BUG #15623: Inconsistent use of default for updatable view

От
Amit Langote
Дата:
Thanks for looking at this.

On Fri, Feb 8, 2019 at 8:01 PM Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>
> On Fri, 8 Feb 2019 at 05:07, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> > Thanks for the report.  Seems odd indeed.
>
> Hmm, indeed. That seems to have been broken ever since updatable views
> were added.
>
> > Looking into this, the reason it works when inserting just one row vs.
> > more than one row is that those two cases are handled by nearby but
> > different pieces of code.  The code that handles multiple rows seems buggy
> > as seen in the above example.  Specifically, I think the bug is in
> > rewriteValuesRTE() which is a function to replace the default placeholders
> > in the input rows by the default values as defined for the target
> > relation.  It is called twice when inserting via the view -- first for the
> > view relation and then again for the underlying table.
>
> Right, except when the view is trigger-updatable. In that case, we do
> have to explicitly set the column value to NULL when
> rewriteValuesRTE() is called for the view, because it won't be called
> again for the underlying table -- it is the trigger's responsibility
> to work how (or indeed if) to update the underlying table. IOW, you
> need to also use view_has_instead_trigger() to check the view,
> otherwise your patch breaks this case:
>
> DROP TABLE IF EXISTS test CASCADE;
> CREATE TABLE test (
>   id int PRIMARY KEY,
>   value int DEFAULT 0
> );
> CREATE VIEW test_view AS (SELECT * FROM test);
>
> CREATE OR REPLACE FUNCTION test_view_ins() RETURNS trigger
> AS
> $$
> BEGIN
>   INSERT INTO test VALUES (NEW.id, NEW.value);
>   RETURN NEW;
> END;
> $$
> LANGUAGE plpgsql;
>
> CREATE TRIGGER test_view_trig INSTEAD OF INSERT ON test_view
>   FOR EACH ROW EXECUTE FUNCTION test_view_ins();
>
> INSERT INTO test_view VALUES (1, DEFAULT), (2, DEFAULT);
>
> ERROR:  unrecognized node type: 142

Oops, I missed this bit.  Updated the patch per your suggestion and
expanded the test case to exercise this.

> While playing around with this, I noticed a related bug affecting the
> new identity columns feature. I've not investigated it fully, but It
> looks almost the same -- if the column is an identity column, and
> we're inserting a multi-row VALUES set containing DEFAULTS, they will
> get rewritten to NULLs which will then lead to an error if overriding
> the generated value isn't allowed:
>
> DROP TABLE IF EXISTS foo CASCADE;
> CREATE TABLE foo
> (
>   a int,
>   b int GENERATED ALWAYS AS IDENTITY
> );
>
> INSERT INTO foo VALUES (1,DEFAULT); -- OK
> INSERT INTO foo VALUES (2,DEFAULT),(3,DEFAULT); -- Fails
>
> I think fixing that should be tackled separately, because it may turn
> out to be subtly different, but it definitely looks like another bug.

I haven't looked into the details of this, but agree about raising a
thread on -hackers about it.

Thanks,
Amit

Вложения

Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Sat, 9 Feb 2019 at 16:57, Amit Langote <amitlangote09@gmail.com> wrote:
> On Fri, Feb 8, 2019 at 8:01 PM Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> > On Fri, 8 Feb 2019 at 05:07, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> > > Looking into this, the reason it works when inserting just one row vs.
> > > more than one row is that those two cases are handled by nearby but
> > > different pieces of code.  The code that handles multiple rows seems buggy
> > > as seen in the above example.  Specifically, I think the bug is in
> > > rewriteValuesRTE() which is a function to replace the default placeholders
> > > in the input rows by the default values as defined for the target
> > > relation.  It is called twice when inserting via the view -- first for the
> > > view relation and then again for the underlying table.
> >
> > Right, except when the view is trigger-updatable...
>
> Oops, I missed this bit.  Updated the patch per your suggestion and
> expanded the test case to exercise this.
>

Unfortunately, that's still not quite right because it makes the
behaviour of single- and multi-row inserts inconsistent for
rule-updatable views. Attached is an updated patch that fixes that. I
adjusted the tests a bit to try to make it clearer which defaults get
applied, and test all possibilities.

However, this is still not the end of the story, because it doesn't
fix the fact that, if the view has a DO ALSO rule on it, single-row
inserts behave differently from multi-row inserts. In that case, each
insert becomes 2 inserts, and defaults need to be treated differently
in each of the 2 queries. That's going to need a little more thought.

Regards,
Dean

Вложения

Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Sun, 10 Feb 2019 at 00:48, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> However, this is still not the end of the story, because it doesn't
> fix the fact that, if the view has a DO ALSO rule on it, single-row
> inserts behave differently from multi-row inserts. In that case, each
> insert becomes 2 inserts, and defaults need to be treated differently
> in each of the 2 queries. That's going to need a little more thought.
>

Here's an updated patch to handle that case.

In case it's not obvious, I'm not intending to try to get this into
next week's updates -- more time is needed to be sure of this fix, and
more pairs of eyes would definitely be helpful, once those updates
have been shipped.

Regards,
Dean

Вложения

Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Sun, 10 Feb 2019 at 11:18, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>
> On Sun, 10 Feb 2019 at 00:48, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> > However, this is still not the end of the story, because it doesn't
> > fix the fact that, if the view has a DO ALSO rule on it, single-row
> > inserts behave differently from multi-row inserts. In that case, each
> > insert becomes 2 inserts, and defaults need to be treated differently
> > in each of the 2 queries. That's going to need a little more thought.
> >
>
> Here's an updated patch to handle that case.
>
> In case it's not obvious, I'm not intending to try to get this into
> next week's updates -- more time is needed to be sure of this fix.

So I did some more testing of this and I'm reasonably happy that this
now fixes the originally reported issue of inconsistent handling of
DEFAULTS in multi-row VALUES lists vs single-row ones. I tested
various other scenarios involving conditional/unconditional
also/instead rules, and I didn't find any other surprises. Attached is
an updated patch with improved comments, and a little less code
duplication.

Regards,
Dean

Вложения

Re: BUG #15623: Inconsistent use of default for updatable view

От
Amit Langote
Дата:
Hi Dean,

On 2019/02/12 19:33, Dean Rasheed wrote:
> On Sun, 10 Feb 2019 at 11:18, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>> On Sun, 10 Feb 2019 at 00:48, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>>> However, this is still not the end of the story, because it doesn't
>>> fix the fact that, if the view has a DO ALSO rule on it, single-row
>>> inserts behave differently from multi-row inserts. In that case, each
>>> insert becomes 2 inserts, and defaults need to be treated differently
>>> in each of the 2 queries. That's going to need a little more thought.
>>>
>>
>> Here's an updated patch to handle that case.
>>
>> In case it's not obvious, I'm not intending to try to get this into
>> next week's updates -- more time is needed to be sure of this fix.
> 
> So I did some more testing of this and I'm reasonably happy that this
> now fixes the originally reported issue of inconsistent handling of
> DEFAULTS in multi-row VALUES lists vs single-row ones. I tested
> various other scenarios involving conditional/unconditional
> also/instead rules, and I didn't find any other surprises. Attached is
> an updated patch with improved comments, and a little less code
> duplication.

Thanks for updating the patch.

I can't really comment on all of the changes that that you made
considering various cases, but became curious if the single-row and
multi-row inserts cases could share the code that determines if the
DEFAULT item be replaced by the target-relation-specified default or NULL?
 IOW, is there some reason why we can't avoid the special handling for the
multi-row (RTE_VALUES) case?

Thanks,
Amit



Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Wed, 13 Feb 2019 at 03:02, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>
> I can't really comment on all of the changes that that you made
> considering various cases, but became curious if the single-row and
> multi-row inserts cases could share the code that determines if the
> DEFAULT item be replaced by the target-relation-specified default or NULL?
>  IOW, is there some reason why we can't avoid the special handling for the
> multi-row (RTE_VALUES) case?
>

No, not as far as I can see.

The tricky part for a multi-row insert is working out what to do when
it sees a DEFAULT, and there is no column default on the target
relation. For an auto-updatable view, it needs to leave the DEFAULT
untouched, so that it can later apply the base relation's column
default when it recurses. For all other kinds of relation, it needs to
turn the DEFAULT into a NULL.

For a single-row insert, that's all much easier. If it sees a DEFAULT,
and there is no column default, it simply omits that entry from the
targetlist. If it then recurses to the base relation, it will put the
targetlist entry back in, if the base relation has a column default.
So it doesn't need to know locally whether it's an auto-updatable
view, and the logic is much simpler. The multi-row case can't easily
do that (add and remove columns) because it's working with a
fixed-width table structure.

Actually, that's not quite the end of it. So far, this has only been
considering INSERT's. I think there are more issues with UPDATE's, but
that's a whole other can of worms. I think I'll commit this first, and
start a thread on -hackers to discuss that.

Regards,
Dean


Re: BUG #15623: Inconsistent use of default for updatable view

От
Amit Langote
Дата:
On 2019/02/13 18:04, Dean Rasheed wrote:
> On Wed, 13 Feb 2019 at 03:02, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>
>> I can't really comment on all of the changes that that you made
>> considering various cases, but became curious if the single-row and
>> multi-row inserts cases could share the code that determines if the
>> DEFAULT item be replaced by the target-relation-specified default or NULL?
>>  IOW, is there some reason why we can't avoid the special handling for the
>> multi-row (RTE_VALUES) case?
>>
> 
> No, not as far as I can see.
> 
> The tricky part for a multi-row insert is working out what to do when
> it sees a DEFAULT, and there is no column default on the target
> relation. For an auto-updatable view, it needs to leave the DEFAULT
> untouched, so that it can later apply the base relation's column
> default when it recurses. For all other kinds of relation, it needs to
> turn the DEFAULT into a NULL.
> 
> For a single-row insert, that's all much easier. If it sees a DEFAULT,
> and there is no column default, it simply omits that entry from the
> targetlist. If it then recurses to the base relation, it will put the
> targetlist entry back in, if the base relation has a column default.
> So it doesn't need to know locally whether it's an auto-updatable
> view, and the logic is much simpler. The multi-row case can't easily
> do that (add and remove columns) because it's working with a
> fixed-width table structure.

Hmm yeah, column sets must be the same in in all value-lists.

> Actually, that's not quite the end of it. So far, this has only been
> considering INSERT's. I think there are more issues with UPDATE's, but
> that's a whole other can of worms. I think I'll commit this first, and
> start a thread on -hackers to discuss that.

Sure, thanks for the explanation.

Regards,
Amit



Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Tue, 12 Feb 2019 at 10:33, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> Here's an updated patch ...

So I pushed that. However, ...

Playing around with it some more, I realised that whilst this appeared
to fix the reported problem, it exposes another issue which is down to
the interaction between rewriteTargetListIU() and rewriteValuesRTE()
--- for an INSERT with a VALUES RTE, rewriteTargetListIU() computes a
list of target attribute numbers (attrno_list) from the targetlist in
its original order, which rewriteValuesRTE() then relies on being the
same length (and in the same order) as each of the lists in the VALUES
RTE. That's OK for the initial invocation of those functions, but it
breaks down when they're recursively invoked for auto-updatable views.

For example, the following test-case, based on a slight variation of
the new regression tests:

create table foo (a int default 1, b int);
create view foo_v as select * from foo;
alter view foo_v alter column b set default 2;
insert into foo_v values (default), (default);

triggers the following Assert in rewriteValuesRTE():

    /* Check list lengths (we can assume all the VALUES sublists are alike) */
    Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));

What's happening is that the initial targetlist, which contains just 1
entry for the column a, gains another entry to set the default for
column b from the view. Then, when it recurses into
rewriteTargetListIU()/rewriteValuesRTE() for the base relation, the
size of the targetlist (now 2) no longer matches the sizes of the
VALUES RTE lists (1).

I think that that failed Assert was unreachable prior to 41531e42d3,
because the old version of rewriteValuesRTE() would always replace all
unresolved DEFAULT items with NULLs, so when it recursed into
rewriteValuesRTE() for the base relation, it would always bail out
early because there would be no DEFAULT items left, and so it would
fail to notice the list size mismatch.

My first thought was that this could be fixed by having
rewriteTargetListIU() compute attrno_list using only those targetlist
entries that refer to the VALUES RTE, and thus omit any new entries
added due to view defaults. That doesn't work though, because that's
not the only way that a list size mismatch can be triggered --- it's
also possible that rewriteTargetListIU() will merge together
targetlist entries, for example if they're array element assignments
referring to the same column, in which case the rewritten targetlist
could be shorter than the VALUES RTE lists, and attempting to compute
attrno_list from it correctly would be trickier.

So actually, I think the right way to fix this is to give up trying to
compute attrno_list in rewriteTargetListIU(), and have
rewriteValuesRTE() work out the attribute assignments itself for each
column of the VALUES RTE by examining the rewritten targetlist. That
looks to be quite straightforward, and results in a cleaner separation
of logic between the 2 functions, per the attached patch.

I think that rewriteValuesRTE() should only ever see DEFAULT items for
columns that are simple assignments to columns of the target relation,
so it only needs to work out the target attribute numbers for TLEs
that contain simple Vars referring to the VALUES RTE. Any DEFAULT seen
in a column not matching that would be an error, but actually I think
such a thing ought to be a "can't happen" error because of the prior
checks during parse analysis, so I've used elog() to report if this
does happen.

Incidentally, it looks like the part of rewriteValuesRTE()'s comment
about subscripted and field assignment has been wrong since
a3c7a993d5, so I've attempted to clarify that. That will need to look
different pre-9.6, I think.

Thoughts?

Regards,
Dean

Вложения

Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Tue, 12 Feb 2019 at 10:33, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> Here's an updated patch ...

So I pushed that. However, ...

Playing around with it some more, I realised that whilst this appeared
to fix the reported problem, it exposes another issue which is down to
the interaction between rewriteTargetListIU() and rewriteValuesRTE()
--- for an INSERT with a VALUES RTE, rewriteTargetListIU() computes a
list of target attribute numbers (attrno_list) from the targetlist in
its original order, which rewriteValuesRTE() then relies on being the
same length (and in the same order) as each of the lists in the VALUES
RTE. That's OK for the initial invocation of those functions, but it
breaks down when they're recursively invoked for auto-updatable views.

For example, the following test-case, based on a slight variation of
the new regression tests:

create table foo (a int default 1, b int);
create view foo_v as select * from foo;
alter view foo_v alter column b set default 2;
insert into foo_v values (default), (default);

triggers the following Assert in rewriteValuesRTE():

    /* Check list lengths (we can assume all the VALUES sublists are alike) */
    Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));

What's happening is that the initial targetlist, which contains just 1
entry for the column a, gains another entry to set the default for
column b from the view. Then, when it recurses into
rewriteTargetListIU()/rewriteValuesRTE() for the base relation, the
size of the targetlist (now 2) no longer matches the sizes of the
VALUES RTE lists (1).

I think that that failed Assert was unreachable prior to 41531e42d3,
because the old version of rewriteValuesRTE() would always replace all
unresolved DEFAULT items with NULLs, so when it recursed into
rewriteValuesRTE() for the base relation, it would always bail out
early because there would be no DEFAULT items left, and so it would
fail to notice the list size mismatch.

My first thought was that this could be fixed by having
rewriteTargetListIU() compute attrno_list using only those targetlist
entries that refer to the VALUES RTE, and thus omit any new entries
added due to view defaults. That doesn't work though, because that's
not the only way that a list size mismatch can be triggered --- it's
also possible that rewriteTargetListIU() will merge together
targetlist entries, for example if they're array element assignments
referring to the same column, in which case the rewritten targetlist
could be shorter than the VALUES RTE lists, and attempting to compute
attrno_list from it correctly would be trickier.

So actually, I think the right way to fix this is to give up trying to
compute attrno_list in rewriteTargetListIU(), and have
rewriteValuesRTE() work out the attribute assignments itself for each
column of the VALUES RTE by examining the rewritten targetlist. That
looks to be quite straightforward, and results in a cleaner separation
of logic between the 2 functions, per the attached patch.

I think that rewriteValuesRTE() should only ever see DEFAULT items for
columns that are simple assignments to columns of the target relation,
so it only needs to work out the target attribute numbers for TLEs
that contain simple Vars referring to the VALUES RTE. Any DEFAULT seen
in a column not matching that would be an error, but actually I think
such a thing ought to be a "can't happen" error because of the prior
checks during parse analysis, so I've used elog() to report if this
does happen.

Incidentally, it looks like the part of rewriteValuesRTE()'s comment
about subscripted and field assignment has been wrong since
a3c7a993d5, so I've attempted to clarify that. That will need to look
different pre-9.6, I think.

Thoughts?

Regards,
Dean

Re: BUG #15623: Inconsistent use of default for updatable view

От
Amit Langote
Дата:
On 2019/02/27 18:37, Dean Rasheed wrote:
> On Tue, 12 Feb 2019 at 10:33, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>> Here's an updated patch ...
> 
> So I pushed that. However, ...
> 
> Playing around with it some more, I realised that whilst this appeared
> to fix the reported problem, it exposes another issue which is down to
> the interaction between rewriteTargetListIU() and rewriteValuesRTE()
> --- for an INSERT with a VALUES RTE, rewriteTargetListIU() computes a
> list of target attribute numbers (attrno_list) from the targetlist in
> its original order, which rewriteValuesRTE() then relies on being the
> same length (and in the same order) as each of the lists in the VALUES
> RTE. That's OK for the initial invocation of those functions, but it
> breaks down when they're recursively invoked for auto-updatable views.
>> So actually, I think the right way to fix this is to give up trying to
> compute attrno_list in rewriteTargetListIU(), and have
> rewriteValuesRTE() work out the attribute assignments itself for each
> column of the VALUES RTE by examining the rewritten targetlist. That
> looks to be quite straightforward, and results in a cleaner separation
> of logic between the 2 functions, per the attached patch.

+1.  Only rewriteValuesRTE needs to use that information, so it's better
to teach it to figure it by itself.

> I think that rewriteValuesRTE() should only ever see DEFAULT items for
> columns that are simple assignments to columns of the target relation,
> so it only needs to work out the target attribute numbers for TLEs
> that contain simple Vars referring to the VALUES RTE. Any DEFAULT seen
> in a column not matching that would be an error, but actually I think
> such a thing ought to be a "can't happen" error because of the prior
> checks during parse analysis, so I've used elog() to report if this
> does happen.

+                if (attrno == 0)
+                    elog(ERROR, "Cannot set value in column %d to
DEFAULT", i);

Maybe: s/Cannot/cannot/g

+        Assert(list_length(sublist) == numattrs);

Isn't this Assert useless, because we're setting numattrs to
list_length(<first-sublist>) and transformInsertStmt ensures that all
sublists are same length?


Thanks,
Amit



Re: BUG #15623: Inconsistent use of default for updatable view

От
Amit Langote
Дата:
On 2019/02/27 18:37, Dean Rasheed wrote:
> On Tue, 12 Feb 2019 at 10:33, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>> Here's an updated patch ...
> 
> So I pushed that. However, ...
> 
> Playing around with it some more, I realised that whilst this appeared
> to fix the reported problem, it exposes another issue which is down to
> the interaction between rewriteTargetListIU() and rewriteValuesRTE()
> --- for an INSERT with a VALUES RTE, rewriteTargetListIU() computes a
> list of target attribute numbers (attrno_list) from the targetlist in
> its original order, which rewriteValuesRTE() then relies on being the
> same length (and in the same order) as each of the lists in the VALUES
> RTE. That's OK for the initial invocation of those functions, but it
> breaks down when they're recursively invoked for auto-updatable views.
>> So actually, I think the right way to fix this is to give up trying to
> compute attrno_list in rewriteTargetListIU(), and have
> rewriteValuesRTE() work out the attribute assignments itself for each
> column of the VALUES RTE by examining the rewritten targetlist. That
> looks to be quite straightforward, and results in a cleaner separation
> of logic between the 2 functions, per the attached patch.

+1.  Only rewriteValuesRTE needs to use that information, so it's better
to teach it to figure it by itself.

> I think that rewriteValuesRTE() should only ever see DEFAULT items for
> columns that are simple assignments to columns of the target relation,
> so it only needs to work out the target attribute numbers for TLEs
> that contain simple Vars referring to the VALUES RTE. Any DEFAULT seen
> in a column not matching that would be an error, but actually I think
> such a thing ought to be a "can't happen" error because of the prior
> checks during parse analysis, so I've used elog() to report if this
> does happen.

+                if (attrno == 0)
+                    elog(ERROR, "Cannot set value in column %d to
DEFAULT", i);

Maybe: s/Cannot/cannot/g

+        Assert(list_length(sublist) == numattrs);

Isn't this Assert useless, because we're setting numattrs to
list_length(<first-sublist>) and transformInsertStmt ensures that all
sublists are same length?


Thanks,
Amit



Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Thu, 28 Feb 2019 at 07:47, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>
> +                if (attrno == 0)
> +                    elog(ERROR, "Cannot set value in column %d to
> DEFAULT", i);
>
> Maybe: s/Cannot/cannot/g
>

Ah yes, you're right. That is the convention.


> +        Assert(list_length(sublist) == numattrs);
>
> Isn't this Assert useless, because we're setting numattrs to
> list_length(<first-sublist>) and transformInsertStmt ensures that all
> sublists are same length?
>

Well possibly I'm being over-paranoid, but given that it may have come
via a previous invocation of rewriteValuesRTE() that may have
completely rebuilt the lists, it seemed best to be sure that it hadn't
done something unexpected. It's about to use that to read from the
attrnos array, so it might read beyond the array bounds if any of the
prior logic was faulty.

Thanks for looking.

Regards,
Dean


Re: BUG #15623: Inconsistent use of default for updatable view

От
Dean Rasheed
Дата:
On Thu, 28 Feb 2019 at 07:47, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>
> +                if (attrno == 0)
> +                    elog(ERROR, "Cannot set value in column %d to
> DEFAULT", i);
>
> Maybe: s/Cannot/cannot/g
>

Ah yes, you're right. That is the convention.


> +        Assert(list_length(sublist) == numattrs);
>
> Isn't this Assert useless, because we're setting numattrs to
> list_length(<first-sublist>) and transformInsertStmt ensures that all
> sublists are same length?
>

Well possibly I'm being over-paranoid, but given that it may have come
via a previous invocation of rewriteValuesRTE() that may have
completely rebuilt the lists, it seemed best to be sure that it hadn't
done something unexpected. It's about to use that to read from the
attrnos array, so it might read beyond the array bounds if any of the
prior logic was faulty.

Thanks for looking.

Regards,
Dean