Adjust some comments about structure properties in pg_stat.h
[pgsql.git] / src / pl / plperl / expected / plperl_trigger.out
blobd4879e2f03b04fbac2c6541b4a86e070b185c93f
1 -- test plperl triggers
2 CREATE TYPE rowcomp as (i int);
3 CREATE TYPE rowcompnest as (rfoo rowcomp);
4 CREATE TABLE trigger_test (
5         i int,
6         v varchar,
7                 foo rowcompnest
8 );
9 CREATE TABLE trigger_test_generated (
10     i int,
11     j int GENERATED ALWAYS AS (i * 2) STORED
13 CREATE OR REPLACE FUNCTION trigger_data() RETURNS trigger LANGUAGE plperl AS $$
15   # make sure keys are sorted for consistent results - perl no longer
16   # hashes in  repeatable fashion across runs
18   sub str {
19           my $val = shift;
21           if (!defined $val)
22           {
23                   return 'NULL';
24           }
25           elsif (ref $val eq 'HASH')
26           {
27                 my $str = '';
28                 foreach my $rowkey (sort keys %$val)
29                 {
30                   $str .= ", " if $str;
31                   my $rowval = str($val->{$rowkey});
32                   $str .= "'$rowkey' => $rowval";
33                 }
34                 return '{'. $str .'}';
35           }
36           elsif (ref $val eq 'ARRAY')
37           {
38                   my $str = '';
39                   for my $argval (@$val)
40                   {
41                           $str .= ", " if $str;
42                           $str .= str($argval);
43                   }
44                   return '['. $str .']';
45           }
46           else
47           {
48                   return "'$val'";
49           }
50   }
52   foreach my $key (sort keys %$_TD)
53   {
55     my $val = $_TD->{$key};
57         # relid is variable, so we can not use it repeatably
58         $val = "bogus:12345" if $key eq 'relid';
60         elog(NOTICE, "\$_TD->\{$key\} = ". str($val));
61   }
62   return undef; # allow statement to proceed;
63 $$;
64 CREATE TRIGGER show_trigger_data_trig
65 BEFORE INSERT OR UPDATE OR DELETE ON trigger_test
66 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
67 insert into trigger_test values(1,'insert', '("(1)")');
68 NOTICE:  $_TD->{argc} = '2'
69 NOTICE:  $_TD->{args} = ['23', 'skidoo']
70 NOTICE:  $_TD->{event} = 'INSERT'
71 NOTICE:  $_TD->{level} = 'ROW'
72 NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
73 NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
74 NOTICE:  $_TD->{relid} = 'bogus:12345'
75 NOTICE:  $_TD->{relname} = 'trigger_test'
76 NOTICE:  $_TD->{table_name} = 'trigger_test'
77 NOTICE:  $_TD->{table_schema} = 'public'
78 NOTICE:  $_TD->{when} = 'BEFORE'
79 update trigger_test set v = 'update' where i = 1;
80 NOTICE:  $_TD->{argc} = '2'
81 NOTICE:  $_TD->{args} = ['23', 'skidoo']
82 NOTICE:  $_TD->{event} = 'UPDATE'
83 NOTICE:  $_TD->{level} = 'ROW'
84 NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
85 NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
86 NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
87 NOTICE:  $_TD->{relid} = 'bogus:12345'
88 NOTICE:  $_TD->{relname} = 'trigger_test'
89 NOTICE:  $_TD->{table_name} = 'trigger_test'
90 NOTICE:  $_TD->{table_schema} = 'public'
91 NOTICE:  $_TD->{when} = 'BEFORE'
92 delete from trigger_test;
93 NOTICE:  $_TD->{argc} = '2'
94 NOTICE:  $_TD->{args} = ['23', 'skidoo']
95 NOTICE:  $_TD->{event} = 'DELETE'
96 NOTICE:  $_TD->{level} = 'ROW'
97 NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
98 NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
99 NOTICE:  $_TD->{relid} = 'bogus:12345'
100 NOTICE:  $_TD->{relname} = 'trigger_test'
101 NOTICE:  $_TD->{table_name} = 'trigger_test'
102 NOTICE:  $_TD->{table_schema} = 'public'
103 NOTICE:  $_TD->{when} = 'BEFORE'
104 DROP TRIGGER show_trigger_data_trig on trigger_test;
105 CREATE TRIGGER show_trigger_data_trig_before
106 BEFORE INSERT OR UPDATE OR DELETE ON trigger_test_generated
107 FOR EACH ROW EXECUTE PROCEDURE trigger_data();
108 CREATE TRIGGER show_trigger_data_trig_after
109 AFTER INSERT OR UPDATE OR DELETE ON trigger_test_generated
110 FOR EACH ROW EXECUTE PROCEDURE trigger_data();
111 insert into trigger_test_generated (i) values (1);
112 NOTICE:  $_TD->{argc} = '0'
113 NOTICE:  $_TD->{event} = 'INSERT'
114 NOTICE:  $_TD->{level} = 'ROW'
115 NOTICE:  $_TD->{name} = 'show_trigger_data_trig_before'
116 NOTICE:  $_TD->{new} = {'i' => '1'}
117 NOTICE:  $_TD->{relid} = 'bogus:12345'
118 NOTICE:  $_TD->{relname} = 'trigger_test_generated'
119 NOTICE:  $_TD->{table_name} = 'trigger_test_generated'
120 NOTICE:  $_TD->{table_schema} = 'public'
121 NOTICE:  $_TD->{when} = 'BEFORE'
122 NOTICE:  $_TD->{argc} = '0'
123 NOTICE:  $_TD->{event} = 'INSERT'
124 NOTICE:  $_TD->{level} = 'ROW'
125 NOTICE:  $_TD->{name} = 'show_trigger_data_trig_after'
126 NOTICE:  $_TD->{new} = {'i' => '1', 'j' => '2'}
127 NOTICE:  $_TD->{relid} = 'bogus:12345'
128 NOTICE:  $_TD->{relname} = 'trigger_test_generated'
129 NOTICE:  $_TD->{table_name} = 'trigger_test_generated'
130 NOTICE:  $_TD->{table_schema} = 'public'
131 NOTICE:  $_TD->{when} = 'AFTER'
132 update trigger_test_generated set i = 11 where i = 1;
133 NOTICE:  $_TD->{argc} = '0'
134 NOTICE:  $_TD->{event} = 'UPDATE'
135 NOTICE:  $_TD->{level} = 'ROW'
136 NOTICE:  $_TD->{name} = 'show_trigger_data_trig_before'
137 NOTICE:  $_TD->{new} = {'i' => '11'}
138 NOTICE:  $_TD->{old} = {'i' => '1', 'j' => '2'}
139 NOTICE:  $_TD->{relid} = 'bogus:12345'
140 NOTICE:  $_TD->{relname} = 'trigger_test_generated'
141 NOTICE:  $_TD->{table_name} = 'trigger_test_generated'
142 NOTICE:  $_TD->{table_schema} = 'public'
143 NOTICE:  $_TD->{when} = 'BEFORE'
144 NOTICE:  $_TD->{argc} = '0'
145 NOTICE:  $_TD->{event} = 'UPDATE'
146 NOTICE:  $_TD->{level} = 'ROW'
147 NOTICE:  $_TD->{name} = 'show_trigger_data_trig_after'
148 NOTICE:  $_TD->{new} = {'i' => '11', 'j' => '22'}
149 NOTICE:  $_TD->{old} = {'i' => '1', 'j' => '2'}
150 NOTICE:  $_TD->{relid} = 'bogus:12345'
151 NOTICE:  $_TD->{relname} = 'trigger_test_generated'
152 NOTICE:  $_TD->{table_name} = 'trigger_test_generated'
153 NOTICE:  $_TD->{table_schema} = 'public'
154 NOTICE:  $_TD->{when} = 'AFTER'
155 delete from trigger_test_generated;
156 NOTICE:  $_TD->{argc} = '0'
157 NOTICE:  $_TD->{event} = 'DELETE'
158 NOTICE:  $_TD->{level} = 'ROW'
159 NOTICE:  $_TD->{name} = 'show_trigger_data_trig_before'
160 NOTICE:  $_TD->{old} = {'i' => '11', 'j' => '22'}
161 NOTICE:  $_TD->{relid} = 'bogus:12345'
162 NOTICE:  $_TD->{relname} = 'trigger_test_generated'
163 NOTICE:  $_TD->{table_name} = 'trigger_test_generated'
164 NOTICE:  $_TD->{table_schema} = 'public'
165 NOTICE:  $_TD->{when} = 'BEFORE'
166 NOTICE:  $_TD->{argc} = '0'
167 NOTICE:  $_TD->{event} = 'DELETE'
168 NOTICE:  $_TD->{level} = 'ROW'
169 NOTICE:  $_TD->{name} = 'show_trigger_data_trig_after'
170 NOTICE:  $_TD->{old} = {'i' => '11', 'j' => '22'}
171 NOTICE:  $_TD->{relid} = 'bogus:12345'
172 NOTICE:  $_TD->{relname} = 'trigger_test_generated'
173 NOTICE:  $_TD->{table_name} = 'trigger_test_generated'
174 NOTICE:  $_TD->{table_schema} = 'public'
175 NOTICE:  $_TD->{when} = 'AFTER'
176 DROP TRIGGER show_trigger_data_trig_before ON trigger_test_generated;
177 DROP TRIGGER show_trigger_data_trig_after ON trigger_test_generated;
178 insert into trigger_test values(1,'insert', '("(1)")');
179 CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test;
180 CREATE TRIGGER show_trigger_data_trig
181 INSTEAD OF INSERT OR UPDATE OR DELETE ON trigger_test_view
182 FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
183 insert into trigger_test_view values(2,'insert', '("(2)")');
184 NOTICE:  $_TD->{argc} = '2'
185 NOTICE:  $_TD->{args} = ['24', 'skidoo view']
186 NOTICE:  $_TD->{event} = 'INSERT'
187 NOTICE:  $_TD->{level} = 'ROW'
188 NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
189 NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '2'}}, 'i' => '2', 'v' => 'insert'}
190 NOTICE:  $_TD->{relid} = 'bogus:12345'
191 NOTICE:  $_TD->{relname} = 'trigger_test_view'
192 NOTICE:  $_TD->{table_name} = 'trigger_test_view'
193 NOTICE:  $_TD->{table_schema} = 'public'
194 NOTICE:  $_TD->{when} = 'INSTEAD OF'
195 update trigger_test_view set v = 'update', foo = '("(3)")' where i = 1;
196 NOTICE:  $_TD->{argc} = '2'
197 NOTICE:  $_TD->{args} = ['24', 'skidoo view']
198 NOTICE:  $_TD->{event} = 'UPDATE'
199 NOTICE:  $_TD->{level} = 'ROW'
200 NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
201 NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '3'}}, 'i' => '1', 'v' => 'update'}
202 NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
203 NOTICE:  $_TD->{relid} = 'bogus:12345'
204 NOTICE:  $_TD->{relname} = 'trigger_test_view'
205 NOTICE:  $_TD->{table_name} = 'trigger_test_view'
206 NOTICE:  $_TD->{table_schema} = 'public'
207 NOTICE:  $_TD->{when} = 'INSTEAD OF'
208 delete from trigger_test_view;
209 NOTICE:  $_TD->{argc} = '2'
210 NOTICE:  $_TD->{args} = ['24', 'skidoo view']
211 NOTICE:  $_TD->{event} = 'DELETE'
212 NOTICE:  $_TD->{level} = 'ROW'
213 NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
214 NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
215 NOTICE:  $_TD->{relid} = 'bogus:12345'
216 NOTICE:  $_TD->{relname} = 'trigger_test_view'
217 NOTICE:  $_TD->{table_name} = 'trigger_test_view'
218 NOTICE:  $_TD->{table_schema} = 'public'
219 NOTICE:  $_TD->{when} = 'INSTEAD OF'
220 DROP VIEW trigger_test_view;
221 delete from trigger_test;
222 DROP FUNCTION trigger_data();
223 CREATE OR REPLACE FUNCTION valid_id() RETURNS trigger AS $$
225     if (($_TD->{new}{i}>=100) || ($_TD->{new}{i}<=0))
226     {
227         return "SKIP";   # Skip INSERT/UPDATE command
228     }
229     elsif ($_TD->{new}{v} ne "immortal")
230     {
231         $_TD->{new}{v} .= "(modified by trigger)";
232                 $_TD->{new}{foo}{rfoo}{i}++;
233         return "MODIFY"; # Modify tuple and proceed INSERT/UPDATE command
234     }
235     else
236     {
237         return;          # Proceed INSERT/UPDATE command
238     }
239 $$ LANGUAGE plperl;
240 CREATE TRIGGER "test_valid_id_trig" BEFORE INSERT OR UPDATE ON trigger_test
241 FOR EACH ROW EXECUTE PROCEDURE "valid_id"();
242 INSERT INTO trigger_test (i, v, foo) VALUES (1,'first line', '("(1)")');
243 INSERT INTO trigger_test (i, v, foo) VALUES (2,'second line', '("(2)")');
244 INSERT INTO trigger_test (i, v, foo) VALUES (3,'third line', '("(3)")');
245 INSERT INTO trigger_test (i, v, foo) VALUES (4,'immortal', '("(4)")');
246 INSERT INTO trigger_test (i, v) VALUES (101,'bad id');
247 SELECT * FROM trigger_test;
248  i |                v                 |   foo   
249 ---+----------------------------------+---------
250  1 | first line(modified by trigger)  | ("(2)")
251  2 | second line(modified by trigger) | ("(3)")
252  3 | third line(modified by trigger)  | ("(4)")
253  4 | immortal                         | ("(4)")
254 (4 rows)
256 UPDATE trigger_test SET i = 5 where i=3;
257 UPDATE trigger_test SET i = 100 where i=1;
258 SELECT * FROM trigger_test;
259  i |                          v                           |   foo   
260 ---+------------------------------------------------------+---------
261  1 | first line(modified by trigger)                      | ("(2)")
262  2 | second line(modified by trigger)                     | ("(3)")
263  4 | immortal                                             | ("(4)")
264  5 | third line(modified by trigger)(modified by trigger) | ("(5)")
265 (4 rows)
267 DROP TRIGGER "test_valid_id_trig" ON trigger_test;
268 CREATE OR REPLACE FUNCTION trigger_recurse() RETURNS trigger AS $$
269         use strict;
271         if ($_TD->{new}{i} == 10000)
272         {
273                 spi_exec_query("insert into trigger_test (i, v) values (20000, 'child');");
275                 if ($_TD->{new}{i} != 10000)
276                 {
277                         die "recursive trigger modified: ". $_TD->{new}{i};
278                 }
279         }
280     return;
281 $$ LANGUAGE plperl;
282 CREATE TRIGGER "test_trigger_recurse" BEFORE INSERT ON trigger_test
283 FOR EACH ROW EXECUTE PROCEDURE "trigger_recurse"();
284 INSERT INTO trigger_test (i, v) values (10000, 'top');
285 SELECT * FROM trigger_test;
286    i   |                          v                           |   foo   
287 -------+------------------------------------------------------+---------
288      1 | first line(modified by trigger)                      | ("(2)")
289      2 | second line(modified by trigger)                     | ("(3)")
290      4 | immortal                                             | ("(4)")
291      5 | third line(modified by trigger)(modified by trigger) | ("(5)")
292  20000 | child                                                | 
293  10000 | top                                                  | 
294 (6 rows)
296 CREATE OR REPLACE FUNCTION immortal() RETURNS trigger AS $$
297     if ($_TD->{old}{v} eq $_TD->{args}[0])
298     {
299         return "SKIP"; # Skip DELETE command
300     }
301     else
302     {
303         return;        # Proceed DELETE command
304     };
305 $$ LANGUAGE plperl;
306 CREATE TRIGGER "immortal_trig" BEFORE DELETE ON trigger_test
307 FOR EACH ROW EXECUTE PROCEDURE immortal('immortal');
308 DELETE FROM trigger_test;
309 SELECT * FROM trigger_test;
310  i |    v     |   foo   
311 ---+----------+---------
312  4 | immortal | ("(4)")
313 (1 row)
315 CREATE FUNCTION direct_trigger() RETURNS trigger AS $$
316     return;
317 $$ LANGUAGE plperl;
318 SELECT direct_trigger();
319 ERROR:  trigger functions can only be called as triggers
320 CONTEXT:  compilation of PL/Perl function "direct_trigger"
321 -- check that SQL run in trigger code can see transition tables
322 CREATE TABLE transition_table_test (id int, name text);
323 INSERT INTO transition_table_test VALUES (1, 'a');
324 CREATE FUNCTION transition_table_test_f() RETURNS trigger LANGUAGE plperl AS
326     my $cursor = spi_query("SELECT * FROM old_table");
327     my $row = spi_fetchrow($cursor);
328     defined($row) || die "expected a row";
329     elog(INFO, "old: " . $row->{id} . " -> " . $row->{name});
330     my $row = spi_fetchrow($cursor);
331     !defined($row) || die "expected no more rows";
333     my $cursor = spi_query("SELECT * FROM new_table");
334     my $row = spi_fetchrow($cursor);
335     defined($row) || die "expected a row";
336     elog(INFO, "new: " . $row->{id} . " -> " . $row->{name});
337     my $row = spi_fetchrow($cursor);
338     !defined($row) || die "expected no more rows";
340     return undef;
342 CREATE TRIGGER a_t AFTER UPDATE ON transition_table_test
343   REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table
344   FOR EACH STATEMENT EXECUTE PROCEDURE transition_table_test_f();
345 UPDATE transition_table_test SET name = 'b';
346 INFO:  old: 1 -> a
347 INFO:  new: 1 -> b
348 DROP TABLE transition_table_test;
349 DROP FUNCTION transition_table_test_f();
350 -- test plperl command triggers
351 create or replace function perlsnitch() returns event_trigger language plperl as $$
352   elog(NOTICE, "perlsnitch: " . $_TD->{event} . " " . $_TD->{tag} . " ");
354 create event trigger perl_a_snitch on ddl_command_start
355    execute procedure perlsnitch();
356 create event trigger perl_b_snitch on ddl_command_end
357    execute procedure perlsnitch();
358 create or replace function foobar() returns int language sql as $$select 1;$$;
359 NOTICE:  perlsnitch: ddl_command_start CREATE FUNCTION 
360 NOTICE:  perlsnitch: ddl_command_end CREATE FUNCTION 
361 alter function foobar() cost 77;
362 NOTICE:  perlsnitch: ddl_command_start ALTER FUNCTION 
363 NOTICE:  perlsnitch: ddl_command_end ALTER FUNCTION 
364 drop function foobar();
365 NOTICE:  perlsnitch: ddl_command_start DROP FUNCTION 
366 NOTICE:  perlsnitch: ddl_command_end DROP FUNCTION 
367 create table foo();
368 NOTICE:  perlsnitch: ddl_command_start CREATE TABLE 
369 NOTICE:  perlsnitch: ddl_command_end CREATE TABLE 
370 drop table foo;
371 NOTICE:  perlsnitch: ddl_command_start DROP TABLE 
372 NOTICE:  perlsnitch: ddl_command_end DROP TABLE 
373 drop event trigger perl_a_snitch;
374 drop event trigger perl_b_snitch;
375 -- dealing with generated columns
376 CREATE FUNCTION generated_test_func1() RETURNS trigger
377 LANGUAGE plperl
378 AS $$
379 $_TD->{new}{j} = 5;  # not allowed
380 return 'MODIFY';
382 CREATE TRIGGER generated_test_trigger1 BEFORE INSERT ON trigger_test_generated
383 FOR EACH ROW EXECUTE PROCEDURE generated_test_func1();
384 TRUNCATE trigger_test_generated;
385 INSERT INTO trigger_test_generated (i) VALUES (1);
386 ERROR:  cannot set generated column "j"
387 CONTEXT:  PL/Perl function "generated_test_func1"
388 SELECT * FROM trigger_test_generated;
389  i | j 
390 ---+---
391 (0 rows)