Thread: rules help

rules help

From
Brook Milligan
Date:
I am trying to create a view with rules to make data entry, etc. more
convenient.  The view must be a union of two tables and the rules must
manipulate the underlying tables.  Everything is fine except for one
thing I need help on.

One table must maintain a unique list of keywords that can be
referenced by >1 row in the second table.  Inserts into the view need
to insert into the keyword list if necessary, but not if not
necessary.  If I simply create the normal insert rule, some inserts to
the view fail because the keyword is not unique.  That would be fine
if either the insert into the keyword table could be conditional on
the lack of the keyword or the entire set of rules could proceed even
if the insert into the keyword table fails.

Apparently, putting a where condition on a rule doesn't work (see
error message below).

Any ideas on how to accomplish this?

Thanks for your help.

Cheers,
Brook

===========================================================================
-- tables

drop sequence rule_table_1_id_seq;
drop table rule_table_1;
create table rule_table_1
(id        serial,name        text,
unique (name)
);

drop sequence rule_table_2_id_seq;
drop table rule_table_2;
create table rule_table_2
(id        serial,table_1_id    int4        references rule_table_1 (id),address    text
);

-- view

drop view rule_view;
create view rule_view as select a.name, b.address from rule_table_1 a, rule_table_2 b
where a.id = b.table_1_id;

-- rules

create rule rule_view_insert_1a as on insert to rule_viewwhere not exists (select id from rule_table_1 where name =
new.name)do insteadinsert into rule_table_1 (name) values (new.name);
 
create rule rule_view_insert_2 as on insert to rule_view do insteadinsert into rule_table_2 (table_1_id, address)
selectid, new.address from rule_table_1 where name = new.name;
 

-- insert

insert into rule_view (name, address) values ('Tom', 'New York');
ERROR:  ExecEvalExpr: unknown expression type 108
insert into rule_view (name, address) values ('Sue', 'Boston');
ERROR:  ExecEvalExpr: unknown expression type 108
insert into rule_view (name, address) values ('Bill', 'Chicago');
ERROR:  ExecEvalExpr: unknown expression type 108
insert into rule_view (name, address) values ('Tom', 'Boston');
ERROR:  ExecEvalExpr: unknown expression type 108
select * from rule_view;
select * from rule_table_1;
select * from rule_table_2;



Re: [SQL] rules help

From
jwieck@debis.com (Jan Wieck)
Date:
Brook Milligan wrote:

>
> I am trying to create a view with rules to make data entry, etc. more
> convenient.  The view must be a union of two tables and the rules must
> manipulate the underlying tables.  Everything is fine except for one
> thing I need help on.
>
> [...]
>
> Apparently, putting a where condition on a rule doesn't work (see
> error message below).

    Looks strange - must dive into soon. But anyway, in your case
    the order in which the rule actions take place is  important.
    So  the entire approach to setup two separate rules is wrong,
    because it is not guaranteed in which order  the  rules  will
    get  applied  later! If the rule inserting into table 2 get's
    applied first, the entry in table 1 might not  be  there  and
    thus,   the   insert  will  become  a  noop  since  the  join
    t1.id+new.address would be empty.

    This is a case where multi action rules are required. And  in
    that case, the qualification must be part of the actions, not
    the entire rule because you want the second action to execute
    allways.

    I got it working, but another very strange thing surfaced and
    absolutely have no clue where that was coming from.

>
> ===========================================================================
> -- tables
> create table rule_table_1
> (
>  id          serial,
>  name        text,
>  unique (name)
> );
>
> create table rule_table_2
> (
>  id          serial,
>  table_1_id  int4      references rule_table_1 (id),
>  address     text
> );
>
> -- view
>
> drop view rule_view;
> create view rule_view as select a.name, b.address from rule_table_1 a, rule_table_2 b
> where a.id = b.table_1_id;
>
> -- rules

    create rule rule_view_ins as on insert to rule_view
      do instead (
        insert into rule_table_1 (name)
            select new.name
            where not exists
            (select a.id from rule_table_1 a where a.name = new.name);
        insert into rule_table_2 (table_1_id, address)
            select b.id, new.address from rule_table_1 b
            where new.name = b.name group by 1;
    );



    The strangeness here is, that (for me) it should work without
    the  GROUP  BY  clause.  But then I got multiple entries into
    table 2. Exactly the number of rows in table 1, but they  all
    referenced the correct entry. So with your test data I got 2x
    Sue in Boston, 3x Bill in Chicago and 3x Tom in Boston.

    The next problem is, that setting up  another  table  with  2
    text fields and doing a

        insert into rule_view select * from addr_data;

    doesn't work at all. Seems the rules aren't triggered and the
    data is stored in the view relation.

    And the final problem is that after defining the above rule a
    select from pg_rules crashes the backend. Oh man - think I've
    held my hands for too long off of the rule system :-(


Jan

--

#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#======================================== jwieck@debis.com (Jan Wieck) #

Re: [SQL] rules help

From
Brook Milligan
Date:
Thanks for the QUICK response, Jan.  I guess I didn't realize one
could put multiple actions in a rule.
      The strangeness here is, that (for me) it should work without      the  GROUP  BY  clause.  But then I got
multipleentries into      table 2. Exactly the number of rows in table 1, but they  all      referenced the correct
entry.So with your test data I got 2x      Sue in Boston, 3x Bill in Chicago and 3x Tom in Boston.
 

I don't see this problem (NetBSD 1.3.2/i386, postgresql 6.4.2).  See
my script below which does what I really want (with one exception).
      The next problem is, that setting up  another  table  with  2      text fields and doing a
   insert into rule_view select * from addr_data;
      doesn't work at all. Seems the rules aren't triggered and the      data is stored in the view relation.

I'll see if I see that, too.
      And the final problem is that after defining the above rule a      select from pg_rules crashes the backend. Oh
man- think I've      held my hands for too long off of the rule system :-(
 

I see the crash, too.

Now, for the one exception.  The delete rule below has one action
commented out, the removal of the original name.  If this is
uncommented, it is still not removed.  Have I misconstrued that action
or is this something else odd?

Thanks again for your help.

Cheers,
Brook

===========================================================================
drop sequence rule_table_1_id_seq;
drop table rule_table_1;
create table rule_table_1
(id        serial,name        text,
unique (name)
);

drop sequence rule_table_2_id_seq;
drop table rule_table_2;
create table rule_table_2
(id        serial,table_1_id    int4        references rule_table_1 (id),address    text
);

drop view rule_view;
create view rule_view as select a.name, b.address from rule_table_1 a, rule_table_2 b
where a.id = b.table_1_id;

create rule rule_view_insert as on insert to rule_view
do instead (       insert into rule_table_1 (name)           select new.name           where not exists
(selecta.id from rule_table_1 a where a.name = new.name);       insert into rule_table_2 (table_1_id, address)
select b.id, new.address from rule_table_1 b           where new.name = b.name group by 1;
 
);

create rule rule_view_delete as on delete to rule_view
do instead (delete from rule_table_2 where table_1_id = (select id from rule_table_1 where name = current.name);
--    delete from rule_table_1 where name = current.name;
);

create rule rule_view_update as on update to rule_view
do instead (update rule_table_2 set address = new.address where table_1_id = (select id from rule_table_1 where name =
current.name);updaterule_table_1 set name = new.name where name = current.name;
 
);

insert into rule_view (name, address) values ('Tom', 'New York');
insert into rule_view (name, address) values ('Sue', 'Boston');
insert into rule_view (name, address) values ('Bill', 'Chicago');
insert into rule_view (name, address) values ('Tom', 'Boston');
select * from rule_view order by name, address;
select * from rule_table_1 order by name;
select * from rule_table_2 order by table_1_id;

update rule_view set address = 'Boston' where name = 'Bill';
select * from rule_view order by name, address;
select * from rule_table_1 order by name;
select * from rule_table_2 order by table_1_id;

delete from rule_view where name = 'Tom';
select * from rule_view order by name, address;
select * from rule_table_1 order by name;
select * from rule_table_2 order by table_1_id;