aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-04-08 19:12:03 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2025-04-08 19:12:03 -0400
commitb1720fe63f344adeb8a75b22e8f31b127c814f35 (patch)
tree3b8d6fc2bad1ccd6b079c1c5b1b0f443876d5371 /src
parentc57971034e69ca5705ac2be893a80ea82aca978b (diff)
downloadpostgresql-b1720fe63f344adeb8a75b22e8f31b127c814f35.tar.gz
postgresql-b1720fe63f344adeb8a75b22e8f31b127c814f35.zip
Move contrib/spi testing from core regression tests to contrib/spi.
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 <tgl@sss.pgh.pa.us> Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://postgr.es/m/3872677.1744077559@sss.pgh.pa.us
Diffstat (limited to 'src')
-rw-r--r--src/test/regress/GNUmakefile22
-rw-r--r--src/test/regress/expected/alter_table.out2
-rw-r--r--src/test/regress/expected/test_setup.out4
-rw-r--r--src/test/regress/expected/triggers.out277
-rw-r--r--src/test/regress/meson.build17
-rw-r--r--src/test/regress/regress.c220
-rw-r--r--src/test/regress/sql/alter_table.sql2
-rw-r--r--src/test/regress/sql/test_setup.sql5
-rw-r--r--src/test/regress/sql/triggers.sql198
9 files changed, 15 insertions, 732 deletions
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index 523be640424..ef2bddf42ca 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -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)
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 8a44321034b..476266e3f4b 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -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
diff --git a/src/test/regress/expected/test_setup.out b/src/test/regress/expected/test_setup.out
index 3d0eeec9960..93a4c2691c1 100644
--- a/src/test/regress/expected/test_setup.out
+++ b/src/test/regress/expected/test_setup.out
@@ -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
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index e6f585d9740..c598dc78518 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -4,146 +4,11 @@
-- 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
--
diff --git a/src/test/regress/meson.build b/src/test/regress/meson.build
index 87b26b4f7ff..1da9e9462a9 100644
--- a/src/test/regress/meson.build
+++ b/src/test/regress/meson.build
@@ -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',
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 0bc0a9221de..837fab6b290 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -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
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8432e8e3d54..5ce9d1e429f 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -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
diff --git a/src/test/regress/sql/test_setup.sql b/src/test/regress/sql/test_setup.sql
index 06b0e2121f8..5854399a028 100644
--- a/src/test/regress/sql/test_setup.sql
+++ b/src/test/regress/sql/test_setup.sql
@@ -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
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index e5a491be7ab..d3d242dd29b 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -6,135 +6,13 @@
\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
--