Move contrib/spi testing from core regression tests to contrib/spi.
authorTom Lane <[email protected]>
Tue, 8 Apr 2025 23:12:03 +0000 (19:12 -0400)
committerTom Lane <[email protected]>
Tue, 8 Apr 2025 23:12:03 +0000 (19:12 -0400)
It's weird to have the core regression tests depending on contrib
code, and coverage testing shows that those test queries add nothing
to the core-code coverage of the core tests.  So pull those test bits
out and put them into ordinary test scripts inside contrib/spi/,
making that more like other contrib modules.

Aside from being structurally nicer, anything we can take out of the
core tests (which are executed multiple times per check-world run)
and put into tests executed only once should be a win.  It doesn't
look like this change will buy a whole lot of milliseconds, but a
cycle saved is a cycle earned.

Also, there is some discussion around possibly removing refint and/or
autoinc altogether.  I don't know if that will happen, but we'd
certainly need to decouple them from the core tests to do so.

The tests for autoinc were quite intertwined with the undocumented
"ttdummy" trigger in regress.c.  That made the tests very hard to
understand and contributed nothing to autoinc's testing either.
So I just deleted ttdummy and rewrote the autoinc tests without it.

I realized while doing this that the description of autoinc in
the SGML docs is not a great description of what the function
actually does, so the patch includes some updates to those docs.

Author: Tom Lane <[email protected]>
Reviewed-by: Heikki Linnakangas <[email protected]>
Discussion: https://postgr.es/m/3872677.1744077559@sss.pgh.pa.us

17 files changed:
contrib/spi/.gitignore [new file with mode: 0644]
contrib/spi/Makefile
contrib/spi/expected/autoinc.out [new file with mode: 0644]
contrib/spi/expected/refint.out [new file with mode: 0644]
contrib/spi/meson.build
contrib/spi/sql/autoinc.sql [new file with mode: 0644]
contrib/spi/sql/refint.sql [new file with mode: 0644]
doc/src/sgml/contrib-spi.sgml
src/test/regress/GNUmakefile
src/test/regress/expected/alter_table.out
src/test/regress/expected/test_setup.out
src/test/regress/expected/triggers.out
src/test/regress/meson.build
src/test/regress/regress.c
src/test/regress/sql/alter_table.sql
src/test/regress/sql/test_setup.sql
src/test/regress/sql/triggers.sql

diff --git a/contrib/spi/.gitignore b/contrib/spi/.gitignore
new file mode 100644 (file)
index 0000000..5dcb3ff
--- /dev/null
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
index c9c34ff38895bff3b253c38f92a0e7873a7f4755..7ccbef8c9265e0adc4102518e71ca4fb818f431a 100644 (file)
@@ -10,6 +10,8 @@ DATA = autoinc--1.0.sql \
        refint--1.0.sql
 PGFILEDESC = "spi - examples of using SPI and triggers"
 
+REGRESS = autoinc refint
+
 DOCS = $(addsuffix .example, $(MODULES))
 
 # this is needed for the regression tests;
diff --git a/contrib/spi/expected/autoinc.out b/contrib/spi/expected/autoinc.out
new file mode 100644 (file)
index 0000000..07ae8ad
--- /dev/null
@@ -0,0 +1,50 @@
+CREATE EXTENSION autoinc;
+create sequence aitest_seq increment 10 start 0 minvalue 0;
+create table aitest (
+   price_id    int4,
+   price_val   int4,
+   price_on    int4
+);
+create trigger aiserial
+   before insert or update on aitest
+   for each row
+   execute procedure
+   autoinc (price_on, aitest_seq);
+insert into aitest values (1, 1, null);
+insert into aitest values (2, 2, 0);
+insert into aitest values (3, 3, 1);
+select * from aitest;
+ price_id | price_val | price_on 
+----------+-----------+----------
+        1 |         1 |       10
+        2 |         2 |       20
+        3 |         3 |        1
+(3 rows)
+
+update aitest set price_on = 11;
+select * from aitest;
+ price_id | price_val | price_on 
+----------+-----------+----------
+        1 |         1 |       11
+        2 |         2 |       11
+        3 |         3 |       11
+(3 rows)
+
+update aitest set price_on = 0;
+select * from aitest;
+ price_id | price_val | price_on 
+----------+-----------+----------
+        1 |         1 |       30
+        2 |         2 |       40
+        3 |         3 |       50
+(3 rows)
+
+update aitest set price_on = null;
+select * from aitest;
+ price_id | price_val | price_on 
+----------+-----------+----------
+        1 |         1 |       60
+        2 |         2 |       70
+        3 |         3 |       80
+(3 rows)
+
diff --git a/contrib/spi/expected/refint.out b/contrib/spi/expected/refint.out
new file mode 100644 (file)
index 0000000..7963360
--- /dev/null
@@ -0,0 +1,113 @@
+CREATE EXTENSION refint;
+create table pkeys (pkey1 int4 not null, pkey2 text not null);
+create table fkeys (fkey1 int4, fkey2 text, fkey3 int);
+create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null);
+create index fkeys_i on fkeys (fkey1, fkey2);
+create index fkeys2_i on fkeys2 (fkey21, fkey22);
+create index fkeys2p_i on fkeys2 (pkey23);
+insert into pkeys values (10, '1');
+insert into pkeys values (20, '2');
+insert into pkeys values (30, '3');
+insert into pkeys values (40, '4');
+insert into pkeys values (50, '5');
+insert into pkeys values (60, '6');
+create unique index pkeys_i on pkeys (pkey1, pkey2);
+--
+-- For fkeys:
+--     (fkey1, fkey2)  --> pkeys (pkey1, pkey2)
+--     (fkey3)     --> fkeys2 (pkey23)
+--
+create trigger check_fkeys_pkey_exist
+   after insert or update on fkeys
+   for each row
+   execute function
+   check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
+create trigger check_fkeys_pkey2_exist
+   after insert or update on fkeys
+   for each row
+   execute function check_primary_key ('fkey3', 'fkeys2', 'pkey23');
+--
+-- For fkeys2:
+--     (fkey21, fkey22)    --> pkeys (pkey1, pkey2)
+--
+create trigger check_fkeys2_pkey_exist
+   after insert or update on fkeys2
+   for each row
+   execute procedure
+   check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
+--
+-- For pkeys:
+--     ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
+--         fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22)
+--
+create trigger check_pkeys_fkey_cascade
+   after delete or update on pkeys
+   for each row
+   execute procedure
+   check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
+   'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
+--
+-- For fkeys2:
+--     ON DELETE/UPDATE (pkey23) RESTRICT:
+--         fkeys (fkey3)
+--
+create trigger check_fkeys2_fkey_restrict
+   after delete or update on fkeys2
+   for each row
+   execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
+insert into fkeys2 values (10, '1', 1);
+insert into fkeys2 values (30, '3', 2);
+insert into fkeys2 values (40, '4', 5);
+insert into fkeys2 values (50, '5', 3);
+-- no key in pkeys
+insert into fkeys2 values (70, '5', 3);
+ERROR:  tuple references non-existent key
+DETAIL:  Trigger "check_fkeys2_pkey_exist" found tuple referencing non-existent key in "pkeys".
+insert into fkeys values (10, '1', 2);
+insert into fkeys values (30, '3', 3);
+insert into fkeys values (40, '4', 2);
+insert into fkeys values (50, '5', 2);
+-- no key in pkeys
+insert into fkeys values (70, '5', 1);
+ERROR:  tuple references non-existent key
+DETAIL:  Trigger "check_fkeys_pkey_exist" found tuple referencing non-existent key in "pkeys".
+-- no key in fkeys2
+insert into fkeys values (60, '6', 4);
+ERROR:  tuple references non-existent key
+DETAIL:  Trigger "check_fkeys_pkey2_exist" found tuple referencing non-existent key in "fkeys2".
+delete from pkeys where pkey1 = 30 and pkey2 = '3';
+NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted
+ERROR:  "check_fkeys2_fkey_restrict": tuple is referenced in "fkeys"
+CONTEXT:  SQL statement "delete from fkeys2 where fkey21 = $1 and fkey22 = $2 "
+delete from pkeys where pkey1 = 40 and pkey2 = '4';
+NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted
+NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are deleted
+update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5';
+NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are updated
+NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are updated
+update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1';
+ERROR:  duplicate key value violates unique constraint "pkeys_i"
+DETAIL:  Key (pkey1, pkey2)=(7, 70) already exists.
+SELECT trigger_name, event_manipulation, event_object_schema, event_object_table,
+       action_order, action_condition, action_orientation, action_timing,
+       action_reference_old_table, action_reference_new_table
+  FROM information_schema.triggers
+  WHERE event_object_table in ('pkeys', 'fkeys', 'fkeys2')
+  ORDER BY trigger_name COLLATE "C", 2;
+        trigger_name        | event_manipulation | event_object_schema | event_object_table | action_order | action_condition | action_orientation | action_timing | action_reference_old_table | action_reference_new_table 
+----------------------------+--------------------+---------------------+--------------------+--------------+------------------+--------------------+---------------+----------------------------+----------------------------
+ check_fkeys2_fkey_restrict | DELETE             | public              | fkeys2             |            1 |                  | ROW                | AFTER         |                            | 
+ check_fkeys2_fkey_restrict | UPDATE             | public              | fkeys2             |            1 |                  | ROW                | AFTER         |                            | 
+ check_fkeys2_pkey_exist    | INSERT             | public              | fkeys2             |            1 |                  | ROW                | AFTER         |                            | 
+ check_fkeys2_pkey_exist    | UPDATE             | public              | fkeys2             |            2 |                  | ROW                | AFTER         |                            | 
+ check_fkeys_pkey2_exist    | INSERT             | public              | fkeys              |            1 |                  | ROW                | AFTER         |                            | 
+ check_fkeys_pkey2_exist    | UPDATE             | public              | fkeys              |            1 |                  | ROW                | AFTER         |                            | 
+ check_fkeys_pkey_exist     | INSERT             | public              | fkeys              |            2 |                  | ROW                | AFTER         |                            | 
+ check_fkeys_pkey_exist     | UPDATE             | public              | fkeys              |            2 |                  | ROW                | AFTER         |                            | 
+ check_pkeys_fkey_cascade   | DELETE             | public              | pkeys              |            1 |                  | ROW                | AFTER         |                            | 
+ check_pkeys_fkey_cascade   | UPDATE             | public              | pkeys              |            1 |                  | ROW                | AFTER         |                            | 
+(10 rows)
+
+DROP TABLE pkeys;
+DROP TABLE fkeys;
+DROP TABLE fkeys2;
index eeab1ab210b69a7c04d89e0821a9398416d5a32d..3832a91019a43c524d5c0ae1b844d419689fef37 100644 (file)
@@ -107,3 +107,15 @@ install_data('refint.control', 'refint--1.0.sql',
 install_data('refint.example',
   kwargs: contrib_doc_args,
 )
+
+tests += {
+  'name': 'spi',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'autoinc',
+      'refint',
+    ],
+  },
+}
diff --git a/contrib/spi/sql/autoinc.sql b/contrib/spi/sql/autoinc.sql
new file mode 100644 (file)
index 0000000..b240dcd
--- /dev/null
@@ -0,0 +1,33 @@
+CREATE EXTENSION autoinc;
+
+create sequence aitest_seq increment 10 start 0 minvalue 0;
+
+create table aitest (
+   price_id    int4,
+   price_val   int4,
+   price_on    int4
+);
+
+create trigger aiserial
+   before insert or update on aitest
+   for each row
+   execute procedure
+   autoinc (price_on, aitest_seq);
+
+insert into aitest values (1, 1, null);
+insert into aitest values (2, 2, 0);
+insert into aitest values (3, 3, 1);
+
+select * from aitest;
+
+update aitest set price_on = 11;
+
+select * from aitest;
+
+update aitest set price_on = 0;
+
+select * from aitest;
+
+update aitest set price_on = null;
+
+select * from aitest;
diff --git a/contrib/spi/sql/refint.sql b/contrib/spi/sql/refint.sql
new file mode 100644 (file)
index 0000000..6345812
--- /dev/null
@@ -0,0 +1,97 @@
+CREATE EXTENSION refint;
+
+create table pkeys (pkey1 int4 not null, pkey2 text not null);
+create table fkeys (fkey1 int4, fkey2 text, fkey3 int);
+create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null);
+
+create index fkeys_i on fkeys (fkey1, fkey2);
+create index fkeys2_i on fkeys2 (fkey21, fkey22);
+create index fkeys2p_i on fkeys2 (pkey23);
+
+insert into pkeys values (10, '1');
+insert into pkeys values (20, '2');
+insert into pkeys values (30, '3');
+insert into pkeys values (40, '4');
+insert into pkeys values (50, '5');
+insert into pkeys values (60, '6');
+create unique index pkeys_i on pkeys (pkey1, pkey2);
+
+--
+-- For fkeys:
+--     (fkey1, fkey2)  --> pkeys (pkey1, pkey2)
+--     (fkey3)     --> fkeys2 (pkey23)
+--
+create trigger check_fkeys_pkey_exist
+   after insert or update on fkeys
+   for each row
+   execute function
+   check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
+
+create trigger check_fkeys_pkey2_exist
+   after insert or update on fkeys
+   for each row
+   execute function check_primary_key ('fkey3', 'fkeys2', 'pkey23');
+
+--
+-- For fkeys2:
+--     (fkey21, fkey22)    --> pkeys (pkey1, pkey2)
+--
+create trigger check_fkeys2_pkey_exist
+   after insert or update on fkeys2
+   for each row
+   execute procedure
+   check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
+
+--
+-- For pkeys:
+--     ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
+--         fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22)
+--
+create trigger check_pkeys_fkey_cascade
+   after delete or update on pkeys
+   for each row
+   execute procedure
+   check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
+   'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
+
+--
+-- For fkeys2:
+--     ON DELETE/UPDATE (pkey23) RESTRICT:
+--         fkeys (fkey3)
+--
+create trigger check_fkeys2_fkey_restrict
+   after delete or update on fkeys2
+   for each row
+   execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
+
+insert into fkeys2 values (10, '1', 1);
+insert into fkeys2 values (30, '3', 2);
+insert into fkeys2 values (40, '4', 5);
+insert into fkeys2 values (50, '5', 3);
+-- no key in pkeys
+insert into fkeys2 values (70, '5', 3);
+
+insert into fkeys values (10, '1', 2);
+insert into fkeys values (30, '3', 3);
+insert into fkeys values (40, '4', 2);
+insert into fkeys values (50, '5', 2);
+-- no key in pkeys
+insert into fkeys values (70, '5', 1);
+-- no key in fkeys2
+insert into fkeys values (60, '6', 4);
+
+delete from pkeys where pkey1 = 30 and pkey2 = '3';
+delete from pkeys where pkey1 = 40 and pkey2 = '4';
+update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5';
+update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1';
+
+SELECT trigger_name, event_manipulation, event_object_schema, event_object_table,
+       action_order, action_condition, action_orientation, action_timing,
+       action_reference_old_table, action_reference_new_table
+  FROM information_schema.triggers
+  WHERE event_object_table in ('pkeys', 'fkeys', 'fkeys2')
+  ORDER BY trigger_name COLLATE "C", 2;
+
+DROP TABLE pkeys;
+DROP TABLE fkeys;
+DROP TABLE fkeys2;
index 55d3fac7a690812e22f8604cac546eb1c471f10f..6fa9479d1b9929d5c147e25f064d20d5217c32aa 100644 (file)
   <para>
    <function>autoinc()</function> is a trigger that stores the next value of
    a sequence into an integer field.  This has some overlap with the
-   built-in <quote>serial column</quote> feature, but it is not the same:
-   <function>autoinc()</function> will override attempts to substitute a
-   different field value during inserts, and optionally it can be
-   used to increment the field during updates, too.
+   built-in <quote>serial column</quote> feature, but it is not the same.
+   The trigger will replace the field's value only if that value is
+   initially zero or null (after the action of the SQL statement that
+   inserted or updated the row).  Also, if the sequence's next value is
+   zero, <function>nextval()</function> will be called a second time in
+   order to obtain a non-zero value.
   </para>
 
   <para>
index 523be6404240336e8311fead52255b9dfb2c67d6..ef2bddf42cabf74db395c96e585168b8e533ba8f 100644 (file)
@@ -87,26 +87,6 @@ installdirs-tests: installdirs
    $(MKDIR_P)  $(patsubst $(srcdir)/%/,'$(DESTDIR)$(pkglibdir)/regress/%',$(sort $(dir $(regress_data_files))))
 
 
-# Get some extra C modules from contrib/spi
-
-all: refint$(DLSUFFIX) autoinc$(DLSUFFIX)
-
-refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
-   cp $< $@
-
-autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
-   cp $< $@
-
-$(top_builddir)/contrib/spi/refint$(DLSUFFIX): | submake-contrib-spi ;
-
-$(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): | submake-contrib-spi ;
-
-submake-contrib-spi: | submake-libpgport submake-generated-headers
-   $(MAKE) -C $(top_builddir)/contrib/spi
-
-.PHONY: submake-contrib-spi
-
-
 ##
 ## Run tests
 ##
@@ -148,7 +128,7 @@ bigcheck: all | temp-install
 
 clean distclean: clean-lib
 # things built by `all' target
-   rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX)
+   rm -f $(OBJS)
    rm -f pg_regress_main.o pg_regress.o pg_regress$(X)
 # things created by various check targets
    rm -rf $(pg_regress_clean_files)
index 8a44321034b6916bf3e785bad4bd898ed84bb2f8..476266e3f4b0358558ce7b4cdc880fe51b4cc042 100644 (file)
@@ -2898,6 +2898,8 @@ select * from my_locks order by 1;
 
 rollback;
 begin;
+create function ttdummy () returns trigger language plpgsql as
+$$ begin return new; end $$;
 create trigger ttdummy
    before delete or update on alterlock
    for each row
index 3d0eeec996038c32bb56bac2721c1f302f6af061..93a4c2691c191592b8a0c33f77a0da10a9f9f247 100644 (file)
@@ -205,10 +205,6 @@ CREATE FUNCTION binary_coercible(oid, oid)
     RETURNS bool
     AS :'regresslib', 'binary_coercible'
     LANGUAGE C STRICT STABLE PARALLEL SAFE;
-CREATE FUNCTION ttdummy ()
-    RETURNS trigger
-    AS :'regresslib'
-    LANGUAGE C;
 -- Use hand-rolled hash functions and operator classes to get predictable
 -- result on different machines.  The hash function for int4 simply returns
 -- the sum of the values passed to it and the one for text returns the length
index e6f585d9740f3fbd1379fb0b6f9ce101882693f7..c598dc78518745a1025605bc18524c4c9c769a58 100644 (file)
 -- directory paths and dlsuffix are passed to us in environment variables
 \getenv libdir PG_LIBDIR
 \getenv dlsuffix PG_DLSUFFIX
-\set autoinclib :libdir '/autoinc' :dlsuffix
-\set refintlib :libdir '/refint' :dlsuffix
 \set regresslib :libdir '/regress' :dlsuffix
-CREATE FUNCTION autoinc ()
-   RETURNS trigger
-   AS :'autoinclib'
-   LANGUAGE C;
-CREATE FUNCTION check_primary_key ()
-   RETURNS trigger
-   AS :'refintlib'
-   LANGUAGE C;
-CREATE FUNCTION check_foreign_key ()
-   RETURNS trigger
-   AS :'refintlib'
-   LANGUAGE C;
 CREATE FUNCTION trigger_return_old ()
         RETURNS trigger
         AS :'regresslib'
         LANGUAGE C;
-CREATE FUNCTION set_ttdummy (int4)
-        RETURNS int4
-        AS :'regresslib'
-        LANGUAGE C STRICT;
-create table pkeys (pkey1 int4 not null, pkey2 text not null);
-create table fkeys (fkey1 int4, fkey2 text, fkey3 int);
-create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null);
-create index fkeys_i on fkeys (fkey1, fkey2);
-create index fkeys2_i on fkeys2 (fkey21, fkey22);
-create index fkeys2p_i on fkeys2 (pkey23);
-insert into pkeys values (10, '1');
-insert into pkeys values (20, '2');
-insert into pkeys values (30, '3');
-insert into pkeys values (40, '4');
-insert into pkeys values (50, '5');
-insert into pkeys values (60, '6');
-create unique index pkeys_i on pkeys (pkey1, pkey2);
---
--- For fkeys:
---     (fkey1, fkey2)  --> pkeys (pkey1, pkey2)
---     (fkey3)     --> fkeys2 (pkey23)
---
-create trigger check_fkeys_pkey_exist
-   after insert or update on fkeys
-   for each row
-   execute function
-   check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
-create trigger check_fkeys_pkey2_exist
-   after insert or update on fkeys
-   for each row
-   execute function check_primary_key ('fkey3', 'fkeys2', 'pkey23');
---
--- For fkeys2:
---     (fkey21, fkey22)    --> pkeys (pkey1, pkey2)
---
-create trigger check_fkeys2_pkey_exist
-   after insert or update on fkeys2
-   for each row
-   execute procedure
-   check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
--- Test comments
-COMMENT ON TRIGGER check_fkeys2_pkey_bad ON fkeys2 IS 'wrong';
-ERROR:  trigger "check_fkeys2_pkey_bad" for table "fkeys2" does not exist
-COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS 'right';
-COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS NULL;
---
--- For pkeys:
---     ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
---         fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22)
---
-create trigger check_pkeys_fkey_cascade
-   after delete or update on pkeys
-   for each row
-   execute procedure
-   check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
-   'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
---
--- For fkeys2:
---     ON DELETE/UPDATE (pkey23) RESTRICT:
---         fkeys (fkey3)
---
-create trigger check_fkeys2_fkey_restrict
-   after delete or update on fkeys2
-   for each row
-   execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
-insert into fkeys2 values (10, '1', 1);
-insert into fkeys2 values (30, '3', 2);
-insert into fkeys2 values (40, '4', 5);
-insert into fkeys2 values (50, '5', 3);
--- no key in pkeys
-insert into fkeys2 values (70, '5', 3);
-ERROR:  tuple references non-existent key
-DETAIL:  Trigger "check_fkeys2_pkey_exist" found tuple referencing non-existent key in "pkeys".
-insert into fkeys values (10, '1', 2);
-insert into fkeys values (30, '3', 3);
-insert into fkeys values (40, '4', 2);
-insert into fkeys values (50, '5', 2);
--- no key in pkeys
-insert into fkeys values (70, '5', 1);
-ERROR:  tuple references non-existent key
-DETAIL:  Trigger "check_fkeys_pkey_exist" found tuple referencing non-existent key in "pkeys".
--- no key in fkeys2
-insert into fkeys values (60, '6', 4);
-ERROR:  tuple references non-existent key
-DETAIL:  Trigger "check_fkeys_pkey2_exist" found tuple referencing non-existent key in "fkeys2".
-delete from pkeys where pkey1 = 30 and pkey2 = '3';
-NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted
-ERROR:  "check_fkeys2_fkey_restrict": tuple is referenced in "fkeys"
-CONTEXT:  SQL statement "delete from fkeys2 where fkey21 = $1 and fkey22 = $2 "
-delete from pkeys where pkey1 = 40 and pkey2 = '4';
-NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted
-NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are deleted
-update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5';
-NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are updated
-NOTICE:  check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are updated
-update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1';
-ERROR:  duplicate key value violates unique constraint "pkeys_i"
-DETAIL:  Key (pkey1, pkey2)=(7, 70) already exists.
-SELECT trigger_name, event_manipulation, event_object_schema, event_object_table,
-       action_order, action_condition, action_orientation, action_timing,
-       action_reference_old_table, action_reference_new_table
-  FROM information_schema.triggers
-  WHERE event_object_table in ('pkeys', 'fkeys', 'fkeys2')
-  ORDER BY trigger_name COLLATE "C", 2;
-        trigger_name        | event_manipulation | event_object_schema | event_object_table | action_order | action_condition | action_orientation | action_timing | action_reference_old_table | action_reference_new_table 
-----------------------------+--------------------+---------------------+--------------------+--------------+------------------+--------------------+---------------+----------------------------+----------------------------
- check_fkeys2_fkey_restrict | DELETE             | public              | fkeys2             |            1 |                  | ROW                | AFTER         |                            | 
- check_fkeys2_fkey_restrict | UPDATE             | public              | fkeys2             |            1 |                  | ROW                | AFTER         |                            | 
- check_fkeys2_pkey_exist    | INSERT             | public              | fkeys2             |            1 |                  | ROW                | AFTER         |                            | 
- check_fkeys2_pkey_exist    | UPDATE             | public              | fkeys2             |            2 |                  | ROW                | AFTER         |                            | 
- check_fkeys_pkey2_exist    | INSERT             | public              | fkeys              |            1 |                  | ROW                | AFTER         |                            | 
- check_fkeys_pkey2_exist    | UPDATE             | public              | fkeys              |            1 |                  | ROW                | AFTER         |                            | 
- check_fkeys_pkey_exist     | INSERT             | public              | fkeys              |            2 |                  | ROW                | AFTER         |                            | 
- check_fkeys_pkey_exist     | UPDATE             | public              | fkeys              |            2 |                  | ROW                | AFTER         |                            | 
- check_pkeys_fkey_cascade   | DELETE             | public              | pkeys              |            1 |                  | ROW                | AFTER         |                            | 
- check_pkeys_fkey_cascade   | UPDATE             | public              | pkeys              |            1 |                  | ROW                | AFTER         |                            | 
-(10 rows)
-
-DROP TABLE pkeys;
-DROP TABLE fkeys;
-DROP TABLE fkeys2;
 -- Check behavior when trigger returns unmodified trigtuple
 create table trigtest (f1 int, f2 text);
 create trigger trigger_return_old
@@ -294,143 +159,6 @@ select * from trigtest;
 (1 row)
 
 drop table trigtest;
-create sequence ttdummy_seq increment 10 start 0 minvalue 0;
-create table tttest (
-   price_id    int4,
-   price_val   int4,
-   price_on    int4,
-   price_off   int4 default 999999
-);
-create trigger ttdummy
-   before delete or update on tttest
-   for each row
-   execute procedure
-   ttdummy (price_on, price_off);
-create trigger ttserial
-   before insert or update on tttest
-   for each row
-   execute procedure
-   autoinc (price_on, ttdummy_seq);
-insert into tttest values (1, 1, null);
-insert into tttest values (2, 2, null);
-insert into tttest values (3, 3, 0);
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        2 |         2 |       20 |    999999
-        3 |         3 |       30 |    999999
-(3 rows)
-
-delete from tttest where price_id = 2;
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        3 |         3 |       30 |    999999
-        2 |         2 |       20 |        40
-(3 rows)
-
--- what do we see ?
--- get current prices
-select * from tttest where price_off = 999999;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        3 |         3 |       30 |    999999
-(2 rows)
-
--- change price for price_id == 3
-update tttest set price_val = 30 where price_id = 3;
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        2 |         2 |       20 |        40
-        3 |        30 |       50 |    999999
-        3 |         3 |       30 |        50
-(4 rows)
-
--- now we want to change pric_id in ALL tuples
--- this gets us not what we need
-update tttest set price_id = 5 where price_id = 3;
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        2 |         2 |       20 |        40
-        3 |         3 |       30 |        50
-        5 |        30 |       60 |    999999
-        3 |        30 |       50 |        60
-(5 rows)
-
--- restore data as before last update:
-select set_ttdummy(0);
- set_ttdummy 
--------------
-           1
-(1 row)
-
-delete from tttest where price_id = 5;
-update tttest set price_off = 999999 where price_val = 30;
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        2 |         2 |       20 |        40
-        3 |         3 |       30 |        50
-        3 |        30 |       50 |    999999
-(4 rows)
-
--- and try change price_id now!
-update tttest set price_id = 5 where price_id = 3;
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        1 |         1 |       10 |    999999
-        2 |         2 |       20 |        40
-        5 |         3 |       30 |        50
-        5 |        30 |       50 |    999999
-(4 rows)
-
--- isn't it what we need ?
-select set_ttdummy(1);
- set_ttdummy 
--------------
-           0
-(1 row)
-
--- we want to correct some "date"
-update tttest set price_on = -1 where price_id = 1;
-ERROR:  ttdummy (tttest): you cannot change price_on and/or price_off columns (use set_ttdummy)
--- but this doesn't work
--- try in this way
-select set_ttdummy(0);
- set_ttdummy 
--------------
-           1
-(1 row)
-
-update tttest set price_on = -1 where price_id = 1;
-select * from tttest;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        2 |         2 |       20 |        40
-        5 |         3 |       30 |        50
-        5 |        30 |       50 |    999999
-        1 |         1 |       -1 |    999999
-(4 rows)
-
--- isn't it what we need ?
--- get price for price_id == 5 as it was @ "date" 35
-select * from tttest where price_on <= 35 and price_off > 35 and price_id = 5;
- price_id | price_val | price_on | price_off 
-----------+-----------+----------+-----------
-        5 |         3 |       30 |        50
-(1 row)
-
-drop table tttest;
-drop sequence ttdummy_seq;
 --
 -- tests for per-statement triggers
 --
@@ -493,6 +221,11 @@ SELECT * FROM main_table ORDER BY a, b;
     |   
 (8 rows)
 
+-- Test comments
+COMMENT ON TRIGGER no_such_trigger ON main_table IS 'wrong';
+ERROR:  trigger "no_such_trigger" for table "main_table" does not exist
+COMMENT ON TRIGGER before_ins_stmt_trig ON main_table IS 'right';
+COMMENT ON TRIGGER before_ins_stmt_trig ON main_table IS NULL;
 --
 -- test triggers with WHEN clause
 --
index 87b26b4f7ff3e403811afcd2ee16d8f969422827..1da9e9462a9afe75f390ca8c95f8e92043c9c101 100644 (file)
@@ -43,23 +43,6 @@ regress_module = shared_module('regress',
 )
 test_install_libs += regress_module
 
-# Get some extra C modules from contrib/spi but mark them as not to be
-# installed.
-# FIXME: avoid the duplication.
-
-autoinc_regress = shared_module('autoinc',
-  ['../../../contrib/spi/autoinc.c'],
-  kwargs: pg_test_mod_args,
-)
-test_install_libs += autoinc_regress
-
-refint_regress = shared_module('refint',
-  ['../../../contrib/spi/refint.c'],
-  c_args: refint_cflags,
-  kwargs: pg_test_mod_args,
-)
-test_install_libs += refint_regress
-
 
 tests += {
   'name': 'regress',
index 0bc0a9221de86b79d72647f63d593ab1d3da3b3a..837fab6b2905ebb1f2db33ad1dba75c1974fb1ab 100644 (file)
@@ -266,226 +266,6 @@ trigger_return_old(PG_FUNCTION_ARGS)
    return PointerGetDatum(tuple);
 }
 
-#define TTDUMMY_INFINITY   999999
-
-static SPIPlanPtr splan = NULL;
-static bool ttoff = false;
-
-PG_FUNCTION_INFO_V1(ttdummy);
-
-Datum
-ttdummy(PG_FUNCTION_ARGS)
-{
-   TriggerData *trigdata = (TriggerData *) fcinfo->context;
-   Trigger    *trigger;        /* to get trigger name */
-   char      **args;           /* arguments */
-   int         attnum[2];      /* fnumbers of start/stop columns */
-   Datum       oldon,
-               oldoff;
-   Datum       newon,
-               newoff;
-   Datum      *cvals;          /* column values */
-   char       *cnulls;         /* column nulls */
-   char       *relname;        /* triggered relation name */
-   Relation    rel;            /* triggered relation */
-   HeapTuple   trigtuple;
-   HeapTuple   newtuple = NULL;
-   HeapTuple   rettuple;
-   TupleDesc   tupdesc;        /* tuple description */
-   int         natts;          /* # of attributes */
-   bool        isnull;         /* to know is some column NULL or not */
-   int         ret;
-   int         i;
-
-   if (!CALLED_AS_TRIGGER(fcinfo))
-       elog(ERROR, "ttdummy: not fired by trigger manager");
-   if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
-       elog(ERROR, "ttdummy: must be fired for row");
-   if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
-       elog(ERROR, "ttdummy: must be fired before event");
-   if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
-       elog(ERROR, "ttdummy: cannot process INSERT event");
-   if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
-       newtuple = trigdata->tg_newtuple;
-
-   trigtuple = trigdata->tg_trigtuple;
-
-   rel = trigdata->tg_relation;
-   relname = SPI_getrelname(rel);
-
-   /* check if TT is OFF for this relation */
-   if (ttoff)                  /* OFF - nothing to do */
-   {
-       pfree(relname);
-       return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple);
-   }
-
-   trigger = trigdata->tg_trigger;
-
-   if (trigger->tgnargs != 2)
-       elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d",
-            relname, trigger->tgnargs);
-
-   args = trigger->tgargs;
-   tupdesc = rel->rd_att;
-   natts = tupdesc->natts;
-
-   for (i = 0; i < 2; i++)
-   {
-       attnum[i] = SPI_fnumber(tupdesc, args[i]);
-       if (attnum[i] <= 0)
-           elog(ERROR, "ttdummy (%s): there is no attribute %s",
-                relname, args[i]);
-       if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID)
-           elog(ERROR, "ttdummy (%s): attribute %s must be of integer type",
-                relname, args[i]);
-   }
-
-   oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
-   if (isnull)
-       elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
-
-   oldoff = SPI_getbinval(trigtuple, tupdesc, attnum[1], &isnull);
-   if (isnull)
-       elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
-
-   if (newtuple != NULL)       /* UPDATE */
-   {
-       newon = SPI_getbinval(newtuple, tupdesc, attnum[0], &isnull);
-       if (isnull)
-           elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]);
-       newoff = SPI_getbinval(newtuple, tupdesc, attnum[1], &isnull);
-       if (isnull)
-           elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]);
-
-       if (oldon != newon || oldoff != newoff)
-           ereport(ERROR,
-                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                    errmsg("ttdummy (%s): you cannot change %s and/or %s columns (use set_ttdummy)",
-                           relname, args[0], args[1])));
-
-       if (newoff != TTDUMMY_INFINITY)
-       {
-           pfree(relname);     /* allocated in upper executor context */
-           return PointerGetDatum(NULL);
-       }
-   }
-   else if (oldoff != TTDUMMY_INFINITY)    /* DELETE */
-   {
-       pfree(relname);
-       return PointerGetDatum(NULL);
-   }
-
-   newoff = DirectFunctionCall1(nextval, CStringGetTextDatum("ttdummy_seq"));
-   /* nextval now returns int64; coerce down to int32 */
-   newoff = Int32GetDatum((int32) DatumGetInt64(newoff));
-
-   /* Connect to SPI manager */
-   SPI_connect();
-
-   /* Fetch tuple values and nulls */
-   cvals = (Datum *) palloc(natts * sizeof(Datum));
-   cnulls = (char *) palloc(natts * sizeof(char));
-   for (i = 0; i < natts; i++)
-   {
-       cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple,
-                                tupdesc, i + 1, &isnull);
-       cnulls[i] = (isnull) ? 'n' : ' ';
-   }
-
-   /* change date column(s) */
-   if (newtuple)               /* UPDATE */
-   {
-       cvals[attnum[0] - 1] = newoff;  /* start_date eq current date */
-       cnulls[attnum[0] - 1] = ' ';
-       cvals[attnum[1] - 1] = TTDUMMY_INFINITY;    /* stop_date eq INFINITY */
-       cnulls[attnum[1] - 1] = ' ';
-   }
-   else
-       /* DELETE */
-   {
-       cvals[attnum[1] - 1] = newoff;  /* stop_date eq current date */
-       cnulls[attnum[1] - 1] = ' ';
-   }
-
-   /* if there is no plan ... */
-   if (splan == NULL)
-   {
-       SPIPlanPtr  pplan;
-       Oid        *ctypes;
-       char       *query;
-
-       /* allocate space in preparation */
-       ctypes = (Oid *) palloc(natts * sizeof(Oid));
-       query = (char *) palloc(100 + 16 * natts);
-
-       /*
-        * Construct query: INSERT INTO _relation_ VALUES ($1, ...)
-        */
-       sprintf(query, "INSERT INTO %s VALUES (", relname);
-       for (i = 1; i <= natts; i++)
-       {
-           sprintf(query + strlen(query), "$%d%s",
-                   i, (i < natts) ? ", " : ")");
-           ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
-       }
-
-       /* Prepare plan for query */
-       pplan = SPI_prepare(query, natts, ctypes);
-       if (pplan == NULL)
-           elog(ERROR, "ttdummy (%s): SPI_prepare returned %s", relname, SPI_result_code_string(SPI_result));
-
-       if (SPI_keepplan(pplan))
-           elog(ERROR, "ttdummy (%s): SPI_keepplan failed", relname);
-
-       splan = pplan;
-   }
-
-   ret = SPI_execp(splan, cvals, cnulls, 0);
-
-   if (ret < 0)
-       elog(ERROR, "ttdummy (%s): SPI_execp returned %d", relname, ret);
-
-   /* Tuple to return to upper Executor ... */
-   if (newtuple)               /* UPDATE */
-       rettuple = SPI_modifytuple(rel, trigtuple, 1, &(attnum[1]), &newoff, NULL);
-   else                        /* DELETE */
-       rettuple = trigtuple;
-
-   SPI_finish();               /* don't forget say Bye to SPI mgr */
-
-   pfree(relname);
-
-   return PointerGetDatum(rettuple);
-}
-
-PG_FUNCTION_INFO_V1(set_ttdummy);
-
-Datum
-set_ttdummy(PG_FUNCTION_ARGS)
-{
-   int32       on = PG_GETARG_INT32(0);
-
-   if (ttoff)                  /* OFF currently */
-   {
-       if (on == 0)
-           PG_RETURN_INT32(0);
-
-       /* turn ON */
-       ttoff = false;
-       PG_RETURN_INT32(0);
-   }
-
-   /* ON currently */
-   if (on != 0)
-       PG_RETURN_INT32(1);
-
-   /* turn OFF */
-   ttoff = true;
-
-   PG_RETURN_INT32(1);
-}
-
 
 /*
  * Type int44 has no real-world use, but the regression tests use it
index 8432e8e3d546f44a143cbd20e08c54f6e5ff13f7..5ce9d1e429f810c777244fe22d620d9af6fde4c2 100644 (file)
@@ -1810,6 +1810,8 @@ select * from my_locks order by 1;
 rollback;
 
 begin;
+create function ttdummy () returns trigger language plpgsql as
+$$ begin return new; end $$;
 create trigger ttdummy
    before delete or update on alterlock
    for each row
index 06b0e2121f895e0dd805cef34b72c7f0c4b24a82..5854399a02803b85c1508b3bb86604665b1acc90 100644 (file)
@@ -252,11 +252,6 @@ CREATE FUNCTION binary_coercible(oid, oid)
     AS :'regresslib', 'binary_coercible'
     LANGUAGE C STRICT STABLE PARALLEL SAFE;
 
-CREATE FUNCTION ttdummy ()
-    RETURNS trigger
-    AS :'regresslib'
-    LANGUAGE C;
-
 -- Use hand-rolled hash functions and operator classes to get predictable
 -- result on different machines.  The hash function for int4 simply returns
 -- the sum of the values passed to it and the one for text returns the length
index e5a491be7abc86b09f411b95bf2bd8060d28c1e2..d3d242dd29b74e1ffeb5ec1025b4e0349501c8ee 100644 (file)
 \getenv libdir PG_LIBDIR
 \getenv dlsuffix PG_DLSUFFIX
 
-\set autoinclib :libdir '/autoinc' :dlsuffix
-\set refintlib :libdir '/refint' :dlsuffix
 \set regresslib :libdir '/regress' :dlsuffix
 
-CREATE FUNCTION autoinc ()
-   RETURNS trigger
-   AS :'autoinclib'
-   LANGUAGE C;
-
-CREATE FUNCTION check_primary_key ()
-   RETURNS trigger
-   AS :'refintlib'
-   LANGUAGE C;
-
-CREATE FUNCTION check_foreign_key ()
-   RETURNS trigger
-   AS :'refintlib'
-   LANGUAGE C;
-
 CREATE FUNCTION trigger_return_old ()
         RETURNS trigger
         AS :'regresslib'
         LANGUAGE C;
 
-CREATE FUNCTION set_ttdummy (int4)
-        RETURNS int4
-        AS :'regresslib'
-        LANGUAGE C STRICT;
-
-create table pkeys (pkey1 int4 not null, pkey2 text not null);
-create table fkeys (fkey1 int4, fkey2 text, fkey3 int);
-create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null);
-
-create index fkeys_i on fkeys (fkey1, fkey2);
-create index fkeys2_i on fkeys2 (fkey21, fkey22);
-create index fkeys2p_i on fkeys2 (pkey23);
-
-insert into pkeys values (10, '1');
-insert into pkeys values (20, '2');
-insert into pkeys values (30, '3');
-insert into pkeys values (40, '4');
-insert into pkeys values (50, '5');
-insert into pkeys values (60, '6');
-create unique index pkeys_i on pkeys (pkey1, pkey2);
-
---
--- For fkeys:
---     (fkey1, fkey2)  --> pkeys (pkey1, pkey2)
---     (fkey3)     --> fkeys2 (pkey23)
---
-create trigger check_fkeys_pkey_exist
-   after insert or update on fkeys
-   for each row
-   execute function
-   check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
-
-create trigger check_fkeys_pkey2_exist
-   after insert or update on fkeys
-   for each row
-   execute function check_primary_key ('fkey3', 'fkeys2', 'pkey23');
-
---
--- For fkeys2:
---     (fkey21, fkey22)    --> pkeys (pkey1, pkey2)
---
-create trigger check_fkeys2_pkey_exist
-   after insert or update on fkeys2
-   for each row
-   execute procedure
-   check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
-
--- Test comments
-COMMENT ON TRIGGER check_fkeys2_pkey_bad ON fkeys2 IS 'wrong';
-COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS 'right';
-COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS NULL;
-
---
--- For pkeys:
---     ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
---         fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22)
---
-create trigger check_pkeys_fkey_cascade
-   after delete or update on pkeys
-   for each row
-   execute procedure
-   check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
-   'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
-
---
--- For fkeys2:
---     ON DELETE/UPDATE (pkey23) RESTRICT:
---         fkeys (fkey3)
---
-create trigger check_fkeys2_fkey_restrict
-   after delete or update on fkeys2
-   for each row
-   execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
-
-insert into fkeys2 values (10, '1', 1);
-insert into fkeys2 values (30, '3', 2);
-insert into fkeys2 values (40, '4', 5);
-insert into fkeys2 values (50, '5', 3);
--- no key in pkeys
-insert into fkeys2 values (70, '5', 3);
-
-insert into fkeys values (10, '1', 2);
-insert into fkeys values (30, '3', 3);
-insert into fkeys values (40, '4', 2);
-insert into fkeys values (50, '5', 2);
--- no key in pkeys
-insert into fkeys values (70, '5', 1);
--- no key in fkeys2
-insert into fkeys values (60, '6', 4);
-
-delete from pkeys where pkey1 = 30 and pkey2 = '3';
-delete from pkeys where pkey1 = 40 and pkey2 = '4';
-update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5';
-update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1';
-
-SELECT trigger_name, event_manipulation, event_object_schema, event_object_table,
-       action_order, action_condition, action_orientation, action_timing,
-       action_reference_old_table, action_reference_new_table
-  FROM information_schema.triggers
-  WHERE event_object_table in ('pkeys', 'fkeys', 'fkeys2')
-  ORDER BY trigger_name COLLATE "C", 2;
-
-DROP TABLE pkeys;
-DROP TABLE fkeys;
-DROP TABLE fkeys2;
 
 -- Check behavior when trigger returns unmodified trigtuple
 create table trigtest (f1 int, f2 text);
@@ -214,77 +92,6 @@ select * from trigtest;
 
 drop table trigtest;
 
-create sequence ttdummy_seq increment 10 start 0 minvalue 0;
-
-create table tttest (
-   price_id    int4,
-   price_val   int4,
-   price_on    int4,
-   price_off   int4 default 999999
-);
-
-create trigger ttdummy
-   before delete or update on tttest
-   for each row
-   execute procedure
-   ttdummy (price_on, price_off);
-
-create trigger ttserial
-   before insert or update on tttest
-   for each row
-   execute procedure
-   autoinc (price_on, ttdummy_seq);
-
-insert into tttest values (1, 1, null);
-insert into tttest values (2, 2, null);
-insert into tttest values (3, 3, 0);
-
-select * from tttest;
-delete from tttest where price_id = 2;
-select * from tttest;
--- what do we see ?
-
--- get current prices
-select * from tttest where price_off = 999999;
-
--- change price for price_id == 3
-update tttest set price_val = 30 where price_id = 3;
-select * from tttest;
-
--- now we want to change pric_id in ALL tuples
--- this gets us not what we need
-update tttest set price_id = 5 where price_id = 3;
-select * from tttest;
-
--- restore data as before last update:
-select set_ttdummy(0);
-delete from tttest where price_id = 5;
-update tttest set price_off = 999999 where price_val = 30;
-select * from tttest;
-
--- and try change price_id now!
-update tttest set price_id = 5 where price_id = 3;
-select * from tttest;
--- isn't it what we need ?
-
-select set_ttdummy(1);
-
--- we want to correct some "date"
-update tttest set price_on = -1 where price_id = 1;
--- but this doesn't work
-
--- try in this way
-select set_ttdummy(0);
-update tttest set price_on = -1 where price_id = 1;
-select * from tttest;
--- isn't it what we need ?
-
--- get price for price_id == 5 as it was @ "date" 35
-select * from tttest where price_on <= 35 and price_off > 35 and price_id = 5;
-
-drop table tttest;
-drop sequence ttdummy_seq;
-
 --
 -- tests for per-statement triggers
 --
@@ -346,6 +153,11 @@ COPY main_table (a, b) FROM stdin;
 
 SELECT * FROM main_table ORDER BY a, b;
 
+-- Test comments
+COMMENT ON TRIGGER no_such_trigger ON main_table IS 'wrong';
+COMMENT ON TRIGGER before_ins_stmt_trig ON main_table IS 'right';
+COMMENT ON TRIGGER before_ins_stmt_trig ON main_table IS NULL;
+
 --
 -- test triggers with WHEN clause
 --