Re: Assigning ROW variable having NULL value to RECORD type variabledoesn't give any structure to the RECORD variable. - Mailing list pgsql-hackers

From Ashutosh Sharma
Subject Re: Assigning ROW variable having NULL value to RECORD type variabledoesn't give any structure to the RECORD variable.
Date
Msg-id CAE9k0Pn6RbHQR_NGHzRu6ZME6cRT+8B3W4cs98H_O4_o272xSw@mail.gmail.com
Whole thread Raw
In response to Re: Assigning ROW variable having NULL value to RECORD type variable doesn't give any structure to the RECORD variable.  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
On Sat, Jan 4, 2020 at 2:09 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Robert Haas <robertmhaas@gmail.com> writes:
> > On Wed, Jan 1, 2020 at 10:50 AM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:
> >> I know this is expected to happen considering the changes done in
> >> above commit because from this commit onwards, NULL value assigned to
> >> any row variable represents a true NULL composite value before this
> >> commit it used to be a tuple with each column having null value in it.
> >> But, the point is, even if the row variable is having a NULL value it
> >> still has a structure associated with it. Shouldn't that structure be
> >> transferred to RECORD variable when it is assigned with a ROW type
> >> variable ? Can we consider this behaviour change as a side effect of
> >> the improvement done in the RECORD type of variable?
>
> > I'm not an expert on this topic. However, I *think* that you're trying
> > to distinguish between two things that are actually the same. If it's
> > a "true NULL," it has no structure; it's just NULL. If it has a
> > structure, then it's really a composite value with a NULL in each
> > defined column, i.e. (NULL, NULL, NULL, ...) for some row type rather
> > than just NULL.
>
> Yeah.  In general, we can't do this, because a null value of type
> RECORD simply hasn't got any information about what specific rowtype
> might be involved.  In the case where the null is of a named composite
> type, rather than RECORD, we could choose to act differently ... but
> I'm not really sure that such a change would be an improvement and not
> just a decrease in consistency.
>
> In any case, plpgsql's prior behavior was an implementation artifact
> with very little to recommend it.  As a concrete example, consider
>
> create table t1(a int, b text);
>
> do $$
> declare x t1; r record;
> begin
>   x := null;
>   r := x;
>   raise notice 'r.a = %', r.a;
> end $$;
>
> do $$
> declare r record;
> begin
>   r := null::t1;
>   raise notice 'r.a = %', r.a;
> end $$;
>
> I assert that in any sanely-defined semantics, these two examples
> should give the same result.  In v11 and up, they both give
> 'record "r" is not assigned yet' ... but in prior versions, they
> gave different results.  I do not want to go back to that.
>
> On the other hand, we now have
>
> do $$
> declare x t1; r record;
> begin
>   x := null;
>   r := x;
>   raise notice 'x.a = %', x.a;
>   raise notice 'r.a = %', r.a;
> end $$;
>
> which gives
>
> NOTICE:  x.a = <NULL>
> ERROR:  record "r" is not assigned yet
>
> which is certainly also inconsistent.  The variable declared as
> being type t1 behaves, for this purpose, as if it contained
> "row(null,null)" not just a simple null.  But if you print it,
> or assign it to something else as a whole, you'll find it just
> contains a simple null.  One way to see that these are different
> states is to do
>
> do $$ declare x t1; begin x := null; raise notice 'x = %', x; end$$;
> NOTICE:  x = <NULL>
>
> versus
>
> do $$ declare x t1; begin x := row(null,null); raise notice 'x = %', x; end$$;
> NOTICE:  x = (,)
>
> And, if you assign a row of nulls to a record-type variable, that works:
>
> do $$
> declare x t1; r record;
> begin
>   x := row(null,null);
>   r := x;
>   raise notice 'x.a = %', x.a;
>   raise notice 'r.a = %', r.a;
> end $$;
>
> which gives
>
> NOTICE:  x.a = <NULL>
> NOTICE:  r.a = <NULL>
>
> If we were to change this behavior, I think it would be tantamount
> to sometimes expanding a simple null to a row of nulls, and I'm
> not sure that's a great idea.
>
> The SQL standard is confusing in this respect, because it seems
> that at least the "x IS [NOT] NULL" construct is defined to
> consider both a "simple NULL" and ROW(NULL,NULL,...) as "null".
> But we've concluded that other parts of the spec do allow for
> a distinction (I'm too lazy to search the archives for relevant
> discussions, but there have been some).  The two things are
> definitely different implementation-wise, so it would be hard
> to hide the difference completely.
>
> Another fun fact is that right now, assignment of any null value
> to a composite plpgsql variable works the same: you can assign a simple
> null of some other composite type, or even a scalar null, and behold you
> get a null composite value without any error.  That's because
> exec_assign_value's DTYPE_REC case pays no attention to the declared
> type of the source value once it's found to be null.  Thus
>
> do $$ declare x t1; begin x := 42; raise notice 'x = %', x; end$$;
> ERROR:  cannot assign non-composite value to a record variable
>
> do $$ declare x t1; begin x := null::int; raise notice 'x = %', x; end$$;
> NOTICE:  x = <NULL>
>
> That's pretty bizarre, and I don't think I'd agree with adopting those
> semantics if we were in a green field.  But if we start paying attention
> to the specific type of a null source value, I bet we're going to break
> some code that works today.
>
> Anyway, maybe this area could be improved, but I'm not fully convinced.
> I definitely do not subscribe to the theory that we need to make it
> work like v10 again.

Okay. Thanks for sharing your thoughts on this.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com



pgsql-hackers by date:

Previous
From: Peter Geoghegan
Date:
Subject: Re: [HACKERS] [WIP] Effective storage of duplicates in B-tree index.
Next
From: Tom Lane
Date:
Subject: Re: pgsql: Add basic TAP tests for psql's tab-completion logic.