Dereferencing a 2-dimensional array in plpgsql

Started by Sven Willenbergerabout 21 years ago6 messagesgeneral
Jump to latest

I am having an issue with trying to dereference a 2-dimensional array in
plpgsql. The idea is to have an setup like:

DECLARE
myarray varchar[][];
myvar char;
BEGIN
--stuff
myarray[1] := ''{value1,value2,value3}'';
myarray[2] := ''{valuea,valueb,valuec}'';

--If I then:

myvar := array[1][1];

--I get a subscript error generated. I have tried everycombination of
array[1:1][1], etc all to no avail.

I have also tried pre-initializing myarray with
myarray := ''{{}}'';

The docs seem to to indicate that a simple myarray[1][2] for example
should work, but that does not hold true in the plpgsql. Is there
another type of initialization that is needed to be done? Any advice?

Sven

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sven Willenberger (#1)
Re: Dereferencing a 2-dimensional array in plpgsql

Sven Willenberger <sven@dmv.com> writes:

I am having an issue with trying to dereference a 2-dimensional array in
plpgsql. The idea is to have an setup like:

DECLARE
myarray varchar[][];
myvar char;
BEGIN
--stuff
myarray[1] := ''{value1,value2,value3}'';
myarray[2] := ''{valuea,valueb,valuec}'';

--If I then:

myvar := array[1][1];

--I get a subscript error generated.

That isn't a two-dimensional array, it's a one-dimensional array with
some curly braces in the element values. Keep in mind that the number
of []s you write in the DECLARE is just decoration --- it's not enforced.
What's determining the actual array shape in this example is the
subscripts you write in the assignments.

regards, tom lane

In reply to: Tom Lane (#2)
Re: Dereferencing a 2-dimensional array in plpgsql

Tom Lane wrote:

Sven Willenberger <sven@dmv.com> writes:

I am having an issue with trying to dereference a 2-dimensional array in
plpgsql. The idea is to have an setup like:

DECLARE
myarray varchar[][];
myvar char;
BEGIN
--stuff
myarray[1] := ''{value1,value2,value3}'';
myarray[2] := ''{valuea,valueb,valuec}'';

--If I then:

myvar := array[1][1];

--I get a subscript error generated.

That isn't a two-dimensional array, it's a one-dimensional array with
some curly braces in the element values. Keep in mind that the number
of []s you write in the DECLARE is just decoration --- it's not enforced.
What's determining the actual array shape in this example is the
subscripts you write in the assignments.

The problem I seem to be having is initializing the array. For example
the following function:
create or replace function temp_keys() returns setof key_tuple as '
DECLARE
myarray varchar[][];
myother varchar;
mytuple key_tuple;
counter int;
BEGIN
myarray[1][1] := ''sven'';
myarray[1][2] := ''key18'';
myarray[1][3] := ''A'';
myarray[2][1] := ''dave'';
myarray[2][2] := ''key18'';
myarray[2][3] := ''B'';
for counter in 1 .. 2 LOOP
myother := myarray[1][2];
RAISE NOTICE ''myother = %'',myother;
END LOOP;
mytuple.carrier := myarray[1][1];
mytuple.prefix := myarray[1][2];
mytuple.rate := myarray[1][3];
RETURN NEXT mytuple;
RETURN;
END;
' LANGUAGE plpgsql;

returns:

select * from temp_keys();
NOTICE: myother = <NULL>
NOTICE: myother = <NULL>
holder | keynum | rating
--------+--------+--------
| |
(1 row)

However I have found that the following construct works, albeit very slowly:

DECLARE
myarray varchar[][];
subarray varchar[];
BEGIN
--initialize the arrays
myarray := ''{}'';
subarray := ''{}'';
myarray[1] := ''{sven,key18,A}'';
myarray[2] := ''{dave,key18,b}'';
subarray := myarray[1];
RAISE NOTICE ''subarray = %'',subarray;
--snip

running this will return 'sven' in the NOTICE section.

The problem stems from being unable to assign values to an array without
first initializing the array in plpgsql. I can initialize
single-dimenstion arrays as noted, but any attempt to initaliaze and
populate 2-dimension arrays results in subscript and or <NULL> entry issues.

This is an offshoot of the moving backward/rewinding a cursor issue
about which I had inquired earlier and trying to load a table into an
array rather than reopening and closing a cursor thousands of times.
Turns out that using the construct above (with 2 arrays) works, but is
actually slower (??!!) than opening a cursor thousands of times.

Sven

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sven Willenberger (#3)
Re: Dereferencing a 2-dimensional array in plpgsql

Sven Willenberger <sven@dmv.com> writes:

The problem stems from being unable to assign values to an array without
first initializing the array in plpgsql.

I think we changed this in 8.0. Before 8.0, trying to assign to an
element of a NULL array yielded a NULL result array, but I think now
we let you produce a one-element array that way.

regards, tom lane

In reply to: Tom Lane (#4)
Re: Dereferencing a 2-dimensional array in plpgsql

Tom Lane wrote:

Sven Willenberger <sven@dmv.com> writes:

The problem stems from being unable to assign values to an array without
first initializing the array in plpgsql.

I think we changed this in 8.0. Before 8.0, trying to assign to an
element of a NULL array yielded a NULL result array, but I think now
we let you produce a one-element array that way.

Using a 8.0 testbox I find that the arrays still need to be initialized:

DECLARE
blah varchar[];
foo varchar;
BEGIN
blah = ''{}'';
blah[1] := ''bar'';
foo := blah[1];
RAISE NOTICE ''blah[1] = %'',foo;
RETURN NULL;
END;

Will raise notice containing "bar".

DECLARE
blah varchar[];
foo varchar;
BEGIN
blah[1] := ''sven'';
foo := blah[1];
RAISE NOTICE ''blah[1] = %'',foo;
RETURN NULL;
END;

Will raise notice containing <null>.

Leaving the subscript off will initialize the variable with empty braces
or values within the braces; failure to have them results in "array
value must start with "{" or dimension information". Also, this only
applies to single-dimension arrays; I cannot find how to initialize
2-dimension arrays. As as a result, the only way I have seen to do this
then is to create 2 arrays, and having one array point to each row, one
by one, of the large master array. Keep in mind this is all in plpgsql.

Sven

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sven Willenberger (#5)
Re: Dereferencing a 2-dimensional array in plpgsql

Sven Willenberger <sven@dmv.com> writes:

Tom Lane wrote:

I think we changed this in 8.0. Before 8.0, trying to assign to an
element of a NULL array yielded a NULL result array, but I think now
we let you produce a one-element array that way.

Using a 8.0 testbox I find that the arrays still need to be initialized:

[ looks at code... ] Hmm, we changed the main executor but missed plpgsql.
I think this is a bug, since plpgsql is now inconsistent with what
happens in a SQL UPDATE command:

regression=# create table foo (f1 int[]);
CREATE TABLE
regression=# insert into foo values(null);
INSERT 155342 1
regression=# update foo set f1[1] = 33;
UPDATE 1
regression=# select * from foo;
f1
------
{33}
(1 row)

regression=#

I'll see about making plpgsql behave similarly for 8.0.2.

regards, tom lane