1

Using postgres 11 I would like to automatically move rows from one table to another. I have setup a query, trigger function, and trigger but my test inserts fail with '0 0' when the trigger is enabled.

  • source table to move rows from is 'cmdb'
  • destination table to move rows to is 'cmdb_attic'
  • condition is when column 'mgmt_ip' = ''
  • entire row should move
  • the table only contains 3 columns: 'hostname', 'mgmt_ip', 'os_type'

The trigger function code I have is:

BEGIN
    WITH moved_rows AS (
        DELETE FROM cmdb
        WHERE mgmt_ip=''
        RETURNING *
    )
    INSERT INTO cmdb_attic
    SELECT * FROM moved_rows;
    RETURN NULL;
END;

I defined a trigger under the table 'cmdb' that fires before on events insert.

When I do a test insert against table 'cmdb' I receive no error message, and nothing is inserted - into either table.

SOLUTION

I deleted my trigger function and trigger from pgAdmin and ran the code Bergi provided below into pgsql and it works.

CREATE FUNCTION redirect_to_attic() RETURNS TRIGGER
AS $$
BEGIN
    IF NEW.mgmt_ip = '' THEN
        INSERT INTO cmdb_attic VALUES (NEW.*);
        RETURN NULL;
    ELSE
        RETURN NEW;
    END IF;
END;
$$ LANGUAGE PLPGSQL;
CREATE TRIGGER redirect
  BEFORE INSERT
  ON cmdb 
  FOR EACH ROW 
  EXECUTE PROCEDURE redirect_to_attic();

EDIT 1 - trigger details from pgsql

inv_net=# select * from pg_trigger;
 tgrelid |    tgname     | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual | tgoldtable | tgnewtable
---------+---------------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+--------+------------+------------
   24623 | move_to_attic |  24618 |      7 | O         | f            |             0 |             0 |            0 | f            | f              |       0 |        | \x     |        |            |
(1 row)

EDIT 2 - test insert and select

With the trigger enabled, below is what I get. If I disable the trigger, my insert works and I can find that row in 'cmdb'.

inv_net=# INSERT INTO cmdb(hostname, mgmt_ip, os_type) VALUES ('testdevice', '', 'ios');
INSERT 0 0

inv_net=# select * from cmdb where hostname='testdevice';
 hostname | mgmt_ip | os_type
----------+---------+---------
(0 rows)

inv_net=# select * from cmdb_attic where hostname='testdevice';
 hostname | mgmt_ip | os_type
----------+---------+---------
(0 rows)

EDIT 3 - Steps Used to Create and Apply Trigger Function and Trigger in pgAdmin4

settings/tabs not listed were not adjusted

  1. Tables > Trigger Functions > Create > Trigger Function
  2. Type name 'move_to_attic'
  3. Code tab: Insert code (from original post)
  4. No other options/settings adjusted
  5. Tables > cmdb > Triggers > Create > Triggers
  6. Type name 'move_to_attic'
  7. Definition tab: Trigger Enabled (yes), Row trigger (yes), Trigger Function public.move_to_attic
  8. Events tab: Fires BEFORE, Events INSERT
  9. Code tab: my code from the Trigger Function is there already
  10. SQL tab: just says "-- No updates."

EDIT 4 - Output on SQL Tabs for Trigger and Trigger Function

trigger function (using Bergi's answer)

-- FUNCTION: public.move_to_attic()

-- DROP FUNCTION public.move_to_attic();

CREATE FUNCTION public.move_to_attic()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$BEGIN
    IF NEW.mgmt_ip='' THEN
        INSERT INTO cmdb_attic SELECT NEW;
        RETURN NULL;
    ELSE
        RETURN NEW;
    END IF;
END;$BODY$;

ALTER FUNCTION public.move_to_attic()
    OWNER TO svc_netops_postgre;

trigger (applied to cmdb)

-- Trigger: move_to_attic

-- DROP TRIGGER move_to_attic ON public.cmdb;

CREATE TRIGGER move_to_attic
    AFTER INSERT
    ON public.cmdb
    FOR EACH ROW
    EXECUTE PROCEDURE public.move_to_attic();
refriedjello
  • 657
  • 8
  • 18
  • My starting point was this post [link](https://stackoverflow.com/questions/2974057/move-data-from-one-table-to-another-postgresql-edition) – refriedjello Nov 14 '19 at 23:47
  • Please show the whole function definition and how you created the trigger – Bergi Nov 14 '19 at 23:48
  • What do you mean by "*my test inserts fail with '0 0'*"? – Bergi Nov 14 '19 at 23:49
  • 1
    An insert trigger needs to return the `NEW` row (possibly modified). If you return `null`, nothing will get inserted. – Bergi Nov 14 '19 at 23:50
  • @Bergi this is true, but only if the trigger is `BEFORE`. If it's `AFTER` then `RETURN null` doesn't change the behaviour and the record still gets inserted. I know the question specifies a `BEFORE` but it's still worth mentioning for future readers – Kamil Gosciminski Nov 15 '19 at 00:08
  • @Bergi I created them using pgAdmin4. Is there a way to dump entire properties of using pgsq? I updated post with what I could find. – refriedjello Nov 15 '19 at 00:18
  • I changed the trigger function code to be RETURN NEW instead of RETURN NULL. My insert into 'cmdb' works now, however it does not move my row over into 'cmdb_attic' – refriedjello Nov 15 '19 at 00:24
  • Can you post the `CREATE TRIGGER` statement you ran? – Z4-tier Nov 15 '19 at 00:24
  • @Z4-tier - I created it all using pgAdmin. Is there a way to dump the entire configs using pgsql? Otherwise I can post screenshots. – refriedjello Nov 15 '19 at 00:25
  • ack... no, I don't think so. Well, `pg_dump` might do the trick, but that might be more trouble than it's worth... – Z4-tier Nov 15 '19 at 00:29
  • @ahxn81 Just navigate to the trigger (part of the table I believe) in pgAdmin and view the "SQL" tab. It should show the definition of the trigger. Same for the trigger function. – Bergi Nov 15 '19 at 00:30
  • @ahxn81 Which row exactly should it move? Are you saying that instead of inserting a row in `cmdb` it should insert it in `cmdb_attic`? – Bergi Nov 15 '19 at 00:32
  • @Bergi - it should move all rows where column "mgmt_ip=''" - ie, where mgmt_ip is blank/null. and yes, basically I want to redirect an insert from cmdb to cmdb_attic where that condition is met. I am working on screenshots from pgAdmin – refriedjello Nov 15 '19 at 00:35
  • @ahxn81 No screenshots please, post text instead. See [SQL tab](https://www.pgadmin.org/docs/pgadmin4/development/tabbed_browser.html) – Bergi Nov 15 '19 at 00:36
  • If you want to redirect the insertion itself already, there won't be any rows in the table that you could "move". – Bergi Nov 15 '19 at 00:40
  • @Bergi - added steps I used to create the TF and T. – refriedjello Nov 15 '19 at 00:46
  • added output of SQL tabs for both the trigger function and the trigger - using Bergi's answer in this thread – refriedjello Nov 15 '19 at 01:04

1 Answers1

1

basically I want to redirect an insert from cmdb to cmdb_attic where that condition is met

The trigger function for that should look like this:

BEGIN
    IF NEW.mgmt_ip = '' THEN
        INSERT INTO cmdb_attic VALUES (NEW.*);
        RETURN NULL;
    ELSE
        RETURN NEW;
    END IF;
END;

(online demo)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Applying that code, and my INSERT statement in pgsql returns with "INSERT 0 0" and my new row does not exist in either table. – refriedjello Nov 15 '19 at 00:54
  • @ahxn81 [It works just fine](https://dbfiddle.uk/?rdbms=postgres_12&fiddle=9725ea115269512b5640be833bfc1bd0) for me. Notice that it still is a `BEFORE` trigger – Bergi Nov 15 '19 at 01:03
  • This worked for me. I deleted my trigger and trigger function and ran the code as you have it on your dbfiddle link and it works great. Thank you! – refriedjello Nov 15 '19 at 01:09