Skip to content

Commit b1720fe

Browse files
committed
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
1 parent c579710 commit b1720fe

File tree

17 files changed

+332
-736
lines changed

17 files changed

+332
-736
lines changed

contrib/spi/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated subdirectories
2+
/log/
3+
/results/
4+
/tmp_check/

contrib/spi/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ DATA = autoinc--1.0.sql \
1010
refint--1.0.sql
1111
PGFILEDESC = "spi - examples of using SPI and triggers"
1212

13+
REGRESS = autoinc refint
14+
1315
DOCS = $(addsuffix .example, $(MODULES))
1416

1517
# this is needed for the regression tests;

contrib/spi/expected/autoinc.out

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
CREATE EXTENSION autoinc;
2+
create sequence aitest_seq increment 10 start 0 minvalue 0;
3+
create table aitest (
4+
price_id int4,
5+
price_val int4,
6+
price_on int4
7+
);
8+
create trigger aiserial
9+
before insert or update on aitest
10+
for each row
11+
execute procedure
12+
autoinc (price_on, aitest_seq);
13+
insert into aitest values (1, 1, null);
14+
insert into aitest values (2, 2, 0);
15+
insert into aitest values (3, 3, 1);
16+
select * from aitest;
17+
price_id | price_val | price_on
18+
----------+-----------+----------
19+
1 | 1 | 10
20+
2 | 2 | 20
21+
3 | 3 | 1
22+
(3 rows)
23+
24+
update aitest set price_on = 11;
25+
select * from aitest;
26+
price_id | price_val | price_on
27+
----------+-----------+----------
28+
1 | 1 | 11
29+
2 | 2 | 11
30+
3 | 3 | 11
31+
(3 rows)
32+
33+
update aitest set price_on = 0;
34+
select * from aitest;
35+
price_id | price_val | price_on
36+
----------+-----------+----------
37+
1 | 1 | 30
38+
2 | 2 | 40
39+
3 | 3 | 50
40+
(3 rows)
41+
42+
update aitest set price_on = null;
43+
select * from aitest;
44+
price_id | price_val | price_on
45+
----------+-----------+----------
46+
1 | 1 | 60
47+
2 | 2 | 70
48+
3 | 3 | 80
49+
(3 rows)
50+

contrib/spi/expected/refint.out

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
CREATE EXTENSION refint;
2+
create table pkeys (pkey1 int4 not null, pkey2 text not null);
3+
create table fkeys (fkey1 int4, fkey2 text, fkey3 int);
4+
create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null);
5+
create index fkeys_i on fkeys (fkey1, fkey2);
6+
create index fkeys2_i on fkeys2 (fkey21, fkey22);
7+
create index fkeys2p_i on fkeys2 (pkey23);
8+
insert into pkeys values (10, '1');
9+
insert into pkeys values (20, '2');
10+
insert into pkeys values (30, '3');
11+
insert into pkeys values (40, '4');
12+
insert into pkeys values (50, '5');
13+
insert into pkeys values (60, '6');
14+
create unique index pkeys_i on pkeys (pkey1, pkey2);
15+
--
16+
-- For fkeys:
17+
-- (fkey1, fkey2) --> pkeys (pkey1, pkey2)
18+
-- (fkey3) --> fkeys2 (pkey23)
19+
--
20+
create trigger check_fkeys_pkey_exist
21+
after insert or update on fkeys
22+
for each row
23+
execute function
24+
check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
25+
create trigger check_fkeys_pkey2_exist
26+
after insert or update on fkeys
27+
for each row
28+
execute function check_primary_key ('fkey3', 'fkeys2', 'pkey23');
29+
--
30+
-- For fkeys2:
31+
-- (fkey21, fkey22) --> pkeys (pkey1, pkey2)
32+
--
33+
create trigger check_fkeys2_pkey_exist
34+
after insert or update on fkeys2
35+
for each row
36+
execute procedure
37+
check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
38+
--
39+
-- For pkeys:
40+
-- ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
41+
-- fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22)
42+
--
43+
create trigger check_pkeys_fkey_cascade
44+
after delete or update on pkeys
45+
for each row
46+
execute procedure
47+
check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
48+
'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
49+
--
50+
-- For fkeys2:
51+
-- ON DELETE/UPDATE (pkey23) RESTRICT:
52+
-- fkeys (fkey3)
53+
--
54+
create trigger check_fkeys2_fkey_restrict
55+
after delete or update on fkeys2
56+
for each row
57+
execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
58+
insert into fkeys2 values (10, '1', 1);
59+
insert into fkeys2 values (30, '3', 2);
60+
insert into fkeys2 values (40, '4', 5);
61+
insert into fkeys2 values (50, '5', 3);
62+
-- no key in pkeys
63+
insert into fkeys2 values (70, '5', 3);
64+
ERROR: tuple references non-existent key
65+
DETAIL: Trigger "check_fkeys2_pkey_exist" found tuple referencing non-existent key in "pkeys".
66+
insert into fkeys values (10, '1', 2);
67+
insert into fkeys values (30, '3', 3);
68+
insert into fkeys values (40, '4', 2);
69+
insert into fkeys values (50, '5', 2);
70+
-- no key in pkeys
71+
insert into fkeys values (70, '5', 1);
72+
ERROR: tuple references non-existent key
73+
DETAIL: Trigger "check_fkeys_pkey_exist" found tuple referencing non-existent key in "pkeys".
74+
-- no key in fkeys2
75+
insert into fkeys values (60, '6', 4);
76+
ERROR: tuple references non-existent key
77+
DETAIL: Trigger "check_fkeys_pkey2_exist" found tuple referencing non-existent key in "fkeys2".
78+
delete from pkeys where pkey1 = 30 and pkey2 = '3';
79+
NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted
80+
ERROR: "check_fkeys2_fkey_restrict": tuple is referenced in "fkeys"
81+
CONTEXT: SQL statement "delete from fkeys2 where fkey21 = $1 and fkey22 = $2 "
82+
delete from pkeys where pkey1 = 40 and pkey2 = '4';
83+
NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted
84+
NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are deleted
85+
update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5';
86+
NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are updated
87+
NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are updated
88+
update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1';
89+
ERROR: duplicate key value violates unique constraint "pkeys_i"
90+
DETAIL: Key (pkey1, pkey2)=(7, 70) already exists.
91+
SELECT trigger_name, event_manipulation, event_object_schema, event_object_table,
92+
action_order, action_condition, action_orientation, action_timing,
93+
action_reference_old_table, action_reference_new_table
94+
FROM information_schema.triggers
95+
WHERE event_object_table in ('pkeys', 'fkeys', 'fkeys2')
96+
ORDER BY trigger_name COLLATE "C", 2;
97+
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
98+
----------------------------+--------------------+---------------------+--------------------+--------------+------------------+--------------------+---------------+----------------------------+----------------------------
99+
check_fkeys2_fkey_restrict | DELETE | public | fkeys2 | 1 | | ROW | AFTER | |
100+
check_fkeys2_fkey_restrict | UPDATE | public | fkeys2 | 1 | | ROW | AFTER | |
101+
check_fkeys2_pkey_exist | INSERT | public | fkeys2 | 1 | | ROW | AFTER | |
102+
check_fkeys2_pkey_exist | UPDATE | public | fkeys2 | 2 | | ROW | AFTER | |
103+
check_fkeys_pkey2_exist | INSERT | public | fkeys | 1 | | ROW | AFTER | |
104+
check_fkeys_pkey2_exist | UPDATE | public | fkeys | 1 | | ROW | AFTER | |
105+
check_fkeys_pkey_exist | INSERT | public | fkeys | 2 | | ROW | AFTER | |
106+
check_fkeys_pkey_exist | UPDATE | public | fkeys | 2 | | ROW | AFTER | |
107+
check_pkeys_fkey_cascade | DELETE | public | pkeys | 1 | | ROW | AFTER | |
108+
check_pkeys_fkey_cascade | UPDATE | public | pkeys | 1 | | ROW | AFTER | |
109+
(10 rows)
110+
111+
DROP TABLE pkeys;
112+
DROP TABLE fkeys;
113+
DROP TABLE fkeys2;

contrib/spi/meson.build

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,15 @@ install_data('refint.control', 'refint--1.0.sql',
107107
install_data('refint.example',
108108
kwargs: contrib_doc_args,
109109
)
110+
111+
tests += {
112+
'name': 'spi',
113+
'sd': meson.current_source_dir(),
114+
'bd': meson.current_build_dir(),
115+
'regress': {
116+
'sql': [
117+
'autoinc',
118+
'refint',
119+
],
120+
},
121+
}

contrib/spi/sql/autoinc.sql

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
CREATE EXTENSION autoinc;
2+
3+
create sequence aitest_seq increment 10 start 0 minvalue 0;
4+
5+
create table aitest (
6+
price_id int4,
7+
price_val int4,
8+
price_on int4
9+
);
10+
11+
create trigger aiserial
12+
before insert or update on aitest
13+
for each row
14+
execute procedure
15+
autoinc (price_on, aitest_seq);
16+
17+
insert into aitest values (1, 1, null);
18+
insert into aitest values (2, 2, 0);
19+
insert into aitest values (3, 3, 1);
20+
21+
select * from aitest;
22+
23+
update aitest set price_on = 11;
24+
25+
select * from aitest;
26+
27+
update aitest set price_on = 0;
28+
29+
select * from aitest;
30+
31+
update aitest set price_on = null;
32+
33+
select * from aitest;

contrib/spi/sql/refint.sql

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
CREATE EXTENSION refint;
2+
3+
create table pkeys (pkey1 int4 not null, pkey2 text not null);
4+
create table fkeys (fkey1 int4, fkey2 text, fkey3 int);
5+
create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null);
6+
7+
create index fkeys_i on fkeys (fkey1, fkey2);
8+
create index fkeys2_i on fkeys2 (fkey21, fkey22);
9+
create index fkeys2p_i on fkeys2 (pkey23);
10+
11+
insert into pkeys values (10, '1');
12+
insert into pkeys values (20, '2');
13+
insert into pkeys values (30, '3');
14+
insert into pkeys values (40, '4');
15+
insert into pkeys values (50, '5');
16+
insert into pkeys values (60, '6');
17+
create unique index pkeys_i on pkeys (pkey1, pkey2);
18+
19+
--
20+
-- For fkeys:
21+
-- (fkey1, fkey2) --> pkeys (pkey1, pkey2)
22+
-- (fkey3) --> fkeys2 (pkey23)
23+
--
24+
create trigger check_fkeys_pkey_exist
25+
after insert or update on fkeys
26+
for each row
27+
execute function
28+
check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
29+
30+
create trigger check_fkeys_pkey2_exist
31+
after insert or update on fkeys
32+
for each row
33+
execute function check_primary_key ('fkey3', 'fkeys2', 'pkey23');
34+
35+
--
36+
-- For fkeys2:
37+
-- (fkey21, fkey22) --> pkeys (pkey1, pkey2)
38+
--
39+
create trigger check_fkeys2_pkey_exist
40+
after insert or update on fkeys2
41+
for each row
42+
execute procedure
43+
check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
44+
45+
--
46+
-- For pkeys:
47+
-- ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
48+
-- fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22)
49+
--
50+
create trigger check_pkeys_fkey_cascade
51+
after delete or update on pkeys
52+
for each row
53+
execute procedure
54+
check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
55+
'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
56+
57+
--
58+
-- For fkeys2:
59+
-- ON DELETE/UPDATE (pkey23) RESTRICT:
60+
-- fkeys (fkey3)
61+
--
62+
create trigger check_fkeys2_fkey_restrict
63+
after delete or update on fkeys2
64+
for each row
65+
execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
66+
67+
insert into fkeys2 values (10, '1', 1);
68+
insert into fkeys2 values (30, '3', 2);
69+
insert into fkeys2 values (40, '4', 5);
70+
insert into fkeys2 values (50, '5', 3);
71+
-- no key in pkeys
72+
insert into fkeys2 values (70, '5', 3);
73+
74+
insert into fkeys values (10, '1', 2);
75+
insert into fkeys values (30, '3', 3);
76+
insert into fkeys values (40, '4', 2);
77+
insert into fkeys values (50, '5', 2);
78+
-- no key in pkeys
79+
insert into fkeys values (70, '5', 1);
80+
-- no key in fkeys2
81+
insert into fkeys values (60, '6', 4);
82+
83+
delete from pkeys where pkey1 = 30 and pkey2 = '3';
84+
delete from pkeys where pkey1 = 40 and pkey2 = '4';
85+
update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5';
86+
update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1';
87+
88+
SELECT trigger_name, event_manipulation, event_object_schema, event_object_table,
89+
action_order, action_condition, action_orientation, action_timing,
90+
action_reference_old_table, action_reference_new_table
91+
FROM information_schema.triggers
92+
WHERE event_object_table in ('pkeys', 'fkeys', 'fkeys2')
93+
ORDER BY trigger_name COLLATE "C", 2;
94+
95+
DROP TABLE pkeys;
96+
DROP TABLE fkeys;
97+
DROP TABLE fkeys2;

doc/src/sgml/contrib-spi.sgml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,12 @@
8181
<para>
8282
<function>autoinc()</function> is a trigger that stores the next value of
8383
a sequence into an integer field. This has some overlap with the
84-
built-in <quote>serial column</quote> feature, but it is not the same:
85-
<function>autoinc()</function> will override attempts to substitute a
86-
different field value during inserts, and optionally it can be
87-
used to increment the field during updates, too.
84+
built-in <quote>serial column</quote> feature, but it is not the same.
85+
The trigger will replace the field's value only if that value is
86+
initially zero or null (after the action of the SQL statement that
87+
inserted or updated the row). Also, if the sequence's next value is
88+
zero, <function>nextval()</function> will be called a second time in
89+
order to obtain a non-zero value.
8890
</para>
8991

9092
<para>

src/test/regress/GNUmakefile

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,26 +87,6 @@ installdirs-tests: installdirs
8787
$(MKDIR_P) $(patsubst $(srcdir)/%/,'$(DESTDIR)$(pkglibdir)/regress/%',$(sort $(dir $(regress_data_files))))
8888

8989

90-
# Get some extra C modules from contrib/spi
91-
92-
all: refint$(DLSUFFIX) autoinc$(DLSUFFIX)
93-
94-
refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
95-
cp $< $@
96-
97-
autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
98-
cp $< $@
99-
100-
$(top_builddir)/contrib/spi/refint$(DLSUFFIX): | submake-contrib-spi ;
101-
102-
$(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): | submake-contrib-spi ;
103-
104-
submake-contrib-spi: | submake-libpgport submake-generated-headers
105-
$(MAKE) -C $(top_builddir)/contrib/spi
106-
107-
.PHONY: submake-contrib-spi
108-
109-
11090
##
11191
## Run tests
11292
##
@@ -148,7 +128,7 @@ bigcheck: all | temp-install
148128

149129
clean distclean: clean-lib
150130
# things built by `all' target
151-
rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX)
131+
rm -f $(OBJS)
152132
rm -f pg_regress_main.o pg_regress.o pg_regress$(X)
153133
# things created by various check targets
154134
rm -rf $(pg_regress_clean_files)

src/test/regress/expected/alter_table.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2898,6 +2898,8 @@ select * from my_locks order by 1;
28982898

28992899
rollback;
29002900
begin;
2901+
create function ttdummy () returns trigger language plpgsql as
2902+
$$ begin return new; end $$;
29012903
create trigger ttdummy
29022904
before delete or update on alterlock
29032905
for each row

src/test/regress/expected/test_setup.out

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,6 @@ CREATE FUNCTION binary_coercible(oid, oid)
205205
RETURNS bool
206206
AS :'regresslib', 'binary_coercible'
207207
LANGUAGE C STRICT STABLE PARALLEL SAFE;
208-
CREATE FUNCTION ttdummy ()
209-
RETURNS trigger
210-
AS :'regresslib'
211-
LANGUAGE C;
212208
-- Use hand-rolled hash functions and operator classes to get predictable
213209
-- result on different machines. The hash function for int4 simply returns
214210
-- the sum of the values passed to it and the one for text returns the length

0 commit comments

Comments
 (0)