Thread: How to access array elements via PL/pgSQL trigger?

How to access array elements via PL/pgSQL trigger?

From
Roland Roberts
Date:
I have a (partial) schema as shown below.  When I attempt to insert a
row from a Tcl script, I get the following error from the script:

NOTICE:  plpgsql: ERROR during compile of exam_statistics_fixup near line 4
ERROR:  parse error at or near "["
        insert into exam (type, school_id, year, population, level)
                  values ('ELA', 4, 1999, 'GE', '{ 7,87,208,73 }')

This is running with PostgreSQL 7.1.3 on both client and server.

It looks like I don't understand something about PL/pgSQL functions
and arrays, but I can't find any examples in the documentation or
anything in the TODO list that would indicate there should be a
problem.  So what *am* I missing?

NB: remove the "references" constraints, and you should be able to run
this example in isolation from the rest of my database.

create table exam (
    type        varchar(4) references exam_type_lookup (type),
    school_id   int references school(id),
    year        numeric(4) not null,
    population  varchar(3) not null,
    total       numeric(4),
    level       numeric(4)[],
    levelpct    numeric(5,2)[]
);

create unique index uk_exam on exam (school_id, year, type, population);
create index idx_exam_1 on exam (school_id);

comment on column exam.type  is 'Type of exam';
comment on column exam.year  is 'Year in which the exam was performed';
comment on column exam.level is 'Number of students performing at the particular level';
comment on column exam.population is 'SE - Special Education, GE - General';

create function exam_statistics_fixup () returns opaque AS '
begin
    -- Force derived columns to be consistent with new data.
    new.total := new.level[1] + new.level[2] + new.level[3] + new.level[4];
    new.levelpct[1] := 100 * new.level[1] / new.total;
    new.levelpct[2] := 100 * new.level[2] / new.total;
    new.levelpct[3] := 100 * new.level[3] / new.total;
    new.levelpct[4] := 100 * new.level[4] / new.total;
    return new;
end;
' language 'plpgsql';

create trigger exam_biur
before insert or update
    on exam
   for each row execute procedure exam_statistics_fixup();




roland
--
               PGP Key ID: 66 BC 3B CD
Roland B. Roberts, PhD                             RL Enterprises
roland@rlenter.com                     76-15 113th Street, Apt 3B
roland@astrofoto.org                       Forest Hills, NY 11375

Re: How to access array elements via PL/pgSQL trigger?

From
Tom Lane
Date:
Roland Roberts <roland@astrofoto.org> writes:
> I have a (partial) schema as shown below.  When I attempt to insert a
> row from a Tcl script, I get the following error from the script:

> NOTICE:  plpgsql: ERROR during compile of exam_statistics_fixup near line 4
> ERROR:  parse error at or near "["

Most likely this error is not coming from plpgsql, but from the core
SQL parser spitting up on some transformed query that plpgsql tried
to feed it.  It'll be educational to set the debug level to 2 or more
(in a fresh backend) and retry the failing query.  That should cause
the postmaster log to accumulate the queries being sent down to the
SQL parser.

My first thought is that plpgsql may not support the syntax
    arrayvar[subscript] := something
but I've not tried it.

            regards, tom lane

Re: How to access array elements via PL/pgSQL trigger?

From
Roland Roberts
Date:
>>>>> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes:

    Tom> Most likely this error is not coming from plpgsql, but from
    Tom> the core SQL parser spitting up on some transformed query
    Tom> that plpgsql tried to feed it.  It'll be educational to set
    Tom> the debug level to 2 or more (in a fresh backend) and retry
    Tom> the failing query.  That should cause the postmaster log to
    Tom> accumulate the queries being sent down to the SQL parser.

I'll try bumping up the debug level tomorrow morning when I'm awake
enough to know what I'm doing....


    Tom> My first thought is that plpgsql may not support the syntax
    Tom>     arrayvar[subscript] := something
    Tom> but I've not tried it.

But line 4 (where it *says* the error is located) reads

    new.total := new.level[1] + ... ;

(which might be a variation of the same thing).

roland
--
               PGP Key ID: 66 BC 3B CD
Roland B. Roberts, PhD                             RL Enterprises
roland@rlenter.com                     76-15 113th Street, Apt 3B
roland@astrofoto.org                       Forest Hills, NY 11375

Re: How to access array elements via PL/pgSQL trigger?

From
Roland Roberts
Date:
Okay, I've re-executed the query after setting debug_level = 2 and
restarting the postmaster to use a log file.  Here is an extract from
the log starting from my connect up to the first aborted insert on the
"exam" table.  All of the activity up to that point is correct (i.e.,
the previous duplicate key errors).

DEBUG:  connection: host=192.168.2.50 user=roland database=psr
DEBUG:  InitPostgres
DEBUG:  StartTransactionCommand
DEBUG:  query: select getdatabaseencoding()
DEBUG:  ProcessQuery
DEBUG:  CommitTransactionCommand
DEBUG:  StartTransactionCommand
DEBUG:  query: insert into district (number, borough) values (22, 'BKLN')
DEBUG:  ProcessQuery
ERROR:  Cannot insert a duplicate key into unique index district_pkey
DEBUG:  AbortCurrentTransaction
DEBUG:  StartTransactionCommand
DEBUG:  query: insert into school (number, district, level) values (312, 22, 'PS')
DEBUG:  ProcessQuery
ERROR:  Cannot insert a duplicate key into unique index uk_school
DEBUG:  AbortCurrentTransaction
DEBUG:  StartTransactionCommand
DEBUG:  query: select id from school where number=312 and district=22 and level='PS'
DEBUG:  ProcessQuery
DEBUG:  CommitTransactionCommand
DEBUG:  StartTransactionCommand
DEBUG:  query: update school set name = 'BERGEN BEACH SCHOOL' where id = 4
DEBUG:  ProcessQuery
DEBUG:  query: SELECT oid FROM ONLY "school_level_lookup" WHERE "id" = $1 FOR UPDATE OF "school_level_lookup"
DEBUG:  query: SELECT oid FROM ONLY "district" WHERE "number" = $1 FOR UPDATE OF "district"
DEBUG:  CommitTransactionCommand
DEBUG:  StartTransactionCommand
DEBUG:  query: insert into exam (type, school_id, year, population, level) values ('ELA', 4, 1999, 'GE', '{ 7,87,208,73
}')
DEBUG:  ProcessQuery
NOTICE:  plpgsql: ERROR during compile of exam_statistics_fixup near line 4
ERROR:  parse error at or near "["
DEBUG:  AbortCurrentTransaction

Does this tell you any more?  Should I log this as a bug?  (The bug
form on the web site doesn't seem to be found right now...).

roland
--
               PGP Key ID: 66 BC 3B CD
Roland B. Roberts, PhD                             RL Enterprises
roland@rlenter.com                     76-15 113th Street, Apt 3B
roland@astrofoto.org                       Forest Hills, NY 11375

Re: How to access array elements via PL/pgSQL trigger?

From
Tom Lane
Date:
Roland Roberts <roland@astrofoto.org> writes:
> DEBUG:  StartTransactionCommand
> DEBUG:  query: insert into exam (type, school_id, year, population, level) values ('ELA', 4, 1999, 'GE', '{
7,87,208,73}') 
> DEBUG:  ProcessQuery
> NOTICE:  plpgsql: ERROR during compile of exam_statistics_fixup near line 4
> ERROR:  parse error at or near "["
> DEBUG:  AbortCurrentTransaction

Okay, so it's not coming from a passed-down query.  I think my original
guess is right: plpgsql doesn't support assignment to array elements.

> Should I log this as a bug?

"Missing feature" would be more like it.  Postgres' array support is
pretty weak in a lot of places, not only plpgsql.

            regards, tom lane

Re: How to access array elements via PL/pgSQL trigger?

From
Roland Roberts
Date:
>>>>> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes:

    >> Should I log this as a bug?

    Tom> "Missing feature" would be more like it.  Postgres' array
    Tom> support is pretty weak in a lot of places, not only plpgsql.

And time to redesign my tables... :-(

roland
--
               PGP Key ID: 66 BC 3B CD
Roland B. Roberts, PhD                             RL Enterprises
roland@rlenter.com                     76-15 113th Street, Apt 3B
roland@astrofoto.org                       Forest Hills, NY 11375