mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add a bunch of pseudo-types to replace the behavior formerly associated
with OPAQUE, as per recent pghackers discussion. I still want to do some more work on the 'cstring' pseudo-type, but I'm going to commit the bulk of the changes now before the tree starts shifting under me ...
This commit is contained in:
@ -6,13 +6,13 @@ CREATE TABLE x (
|
||||
e text
|
||||
);
|
||||
NOTICE: CREATE TABLE will create implicit sequence 'x_a_seq' for SERIAL column 'x.a'
|
||||
CREATE FUNCTION fn_x_before () RETURNS OPAQUE AS '
|
||||
CREATE FUNCTION fn_x_before () RETURNS TRIGGER AS '
|
||||
BEGIN
|
||||
NEW.e := ''before trigger fired''::text;
|
||||
return NEW;
|
||||
END;
|
||||
' language 'plpgsql';
|
||||
CREATE FUNCTION fn_x_after () RETURNS OPAQUE AS '
|
||||
CREATE FUNCTION fn_x_after () RETURNS TRIGGER AS '
|
||||
BEGIN
|
||||
UPDATE x set e=''after trigger fired'' where c=''stuff'';
|
||||
return NULL;
|
||||
|
@ -14,18 +14,39 @@ CREATE TYPE city_budget (
|
||||
element = int4
|
||||
);
|
||||
-- Test type-related default values (broken in releases before PG 7.2)
|
||||
-- Make dummy I/O routines using the existing internal support for int4, text
|
||||
CREATE FUNCTION int42_in(cstring)
|
||||
RETURNS int42
|
||||
AS 'int4in'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
WARNING: ProcedureCreate: type int42 is not yet defined
|
||||
CREATE FUNCTION int42_out(int42)
|
||||
RETURNS cstring
|
||||
AS 'int4out'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
WARNING: Argument type "int42" is only a shell
|
||||
CREATE FUNCTION text_w_default_in(cstring)
|
||||
RETURNS text_w_default
|
||||
AS 'textin'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
WARNING: ProcedureCreate: type text_w_default is not yet defined
|
||||
CREATE FUNCTION text_w_default_out(text_w_default)
|
||||
RETURNS cstring
|
||||
AS 'textout'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
WARNING: Argument type "text_w_default" is only a shell
|
||||
CREATE TYPE int42 (
|
||||
internallength = 4,
|
||||
input = int4in,
|
||||
output = int4out,
|
||||
input = int42_in,
|
||||
output = int42_out,
|
||||
alignment = int4,
|
||||
default = 42,
|
||||
passedbyvalue
|
||||
);
|
||||
CREATE TYPE text_w_default (
|
||||
internallength = variable,
|
||||
input = textin,
|
||||
output = textout,
|
||||
input = text_w_default_in,
|
||||
output = text_w_default_out,
|
||||
alignment = int4,
|
||||
default = 'zippo'
|
||||
);
|
||||
|
@ -16,16 +16,23 @@
|
||||
-- that test creates some bogus operators...
|
||||
-- **************** pg_proc ****************
|
||||
-- Look for illegal values in pg_proc fields.
|
||||
-- NOTE: currently there are a few pg_proc entries that have prorettype = 0.
|
||||
-- Someday that ought to be cleaned up.
|
||||
-- NOTE: in reality pronargs could be more than 10, but I'm too lazy to put
|
||||
-- a larger number of proargtypes check clauses in here. If we ever have
|
||||
-- more-than-10-arg functions in the standard catalogs, extend this query.
|
||||
SELECT p1.oid, p1.proname
|
||||
FROM pg_proc as p1
|
||||
WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR
|
||||
p1.pronargs < 0 OR p1.pronargs > 16)
|
||||
AND p1.proname !~ '^pl[^_]+_call_handler$'
|
||||
AND p1.proname !~ '^RI_FKey_'
|
||||
AND p1.proname !~ 'costestimate$'
|
||||
AND p1.proname != 'update_pg_pwd_and_pg_group';
|
||||
WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
||||
p1.pronargs < 0 OR p1.pronargs > 10 OR
|
||||
(p1.proargtypes[0] = 0 AND p1.pronargs > 0) OR
|
||||
(p1.proargtypes[1] = 0 AND p1.pronargs > 1) OR
|
||||
(p1.proargtypes[2] = 0 AND p1.pronargs > 2) OR
|
||||
(p1.proargtypes[3] = 0 AND p1.pronargs > 3) OR
|
||||
(p1.proargtypes[4] = 0 AND p1.pronargs > 4) OR
|
||||
(p1.proargtypes[5] = 0 AND p1.pronargs > 5) OR
|
||||
(p1.proargtypes[6] = 0 AND p1.pronargs > 6) OR
|
||||
(p1.proargtypes[7] = 0 AND p1.pronargs > 7) OR
|
||||
(p1.proargtypes[8] = 0 AND p1.pronargs > 8) OR
|
||||
(p1.proargtypes[9] = 0 AND p1.pronargs > 9);
|
||||
oid | proname
|
||||
-----+---------
|
||||
(0 rows)
|
||||
@ -217,7 +224,7 @@ WHERE c.castfunc = 0 AND NOT c.castimplicit;
|
||||
SELECT *
|
||||
FROM pg_cast c
|
||||
WHERE c.castfunc = 0 AND
|
||||
NOT EXISTS (SELECT * FROM pg_cast k
|
||||
NOT EXISTS (SELECT 1 FROM pg_cast k
|
||||
WHERE k.castfunc = 0 AND
|
||||
k.castsource = c.casttarget AND
|
||||
k.casttarget = c.castsource);
|
||||
@ -341,7 +348,7 @@ WHERE p1.oprlsortop != 0 AND
|
||||
|
||||
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
|
||||
WHERE p1.oprlsortop != 0 AND NOT
|
||||
EXISTS(SELECT * FROM pg_operator AS p2 WHERE
|
||||
EXISTS(SELECT 1 FROM pg_operator AS p2 WHERE
|
||||
p2.oprname = '<' AND
|
||||
p2.oprleft = p1.oprleft AND
|
||||
p2.oprright = p1.oprright AND
|
||||
@ -352,7 +359,7 @@ WHERE p1.oprlsortop != 0 AND NOT
|
||||
|
||||
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
|
||||
WHERE p1.oprlsortop != 0 AND NOT
|
||||
EXISTS(SELECT * FROM pg_operator AS p2 WHERE
|
||||
EXISTS(SELECT 1 FROM pg_operator AS p2 WHERE
|
||||
p2.oprname = '>' AND
|
||||
p2.oprleft = p1.oprleft AND
|
||||
p2.oprright = p1.oprright AND
|
||||
@ -468,15 +475,17 @@ WHERE p1.oprcode = p2.oid AND
|
||||
-- If oprrest is set, the operator must return boolean,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a restriction selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque, int4)
|
||||
-- The proc signature we want is: float8 proc(internal, oid, internal, int4)
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
WHERE p1.oprrest = p2.oid AND
|
||||
(p1.oprresult != 'bool'::regtype OR
|
||||
p2.prorettype != 'float8'::regtype OR p2.proretset OR
|
||||
p2.pronargs != 4 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 'int4'::regtype);
|
||||
p2.proargtypes[0] != 'internal'::regtype OR
|
||||
p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 'internal'::regtype OR
|
||||
p2.proargtypes[3] != 'int4'::regtype);
|
||||
oid | oprname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
@ -484,15 +493,16 @@ WHERE p1.oprrest = p2.oid AND
|
||||
-- If oprjoin is set, the operator must be a binary boolean op,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a join selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque)
|
||||
-- The proc signature we want is: float8 proc(internal, oid, internal)
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
WHERE p1.oprjoin = p2.oid AND
|
||||
(p1.oprkind != 'b' OR p1.oprresult != 'bool'::regtype OR
|
||||
p2.prorettype != 'float8'::regtype OR p2.proretset OR
|
||||
p2.pronargs != 3 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 0);
|
||||
p2.proargtypes[0] != 'internal'::regtype OR
|
||||
p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 'internal'::regtype);
|
||||
oid | oprname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
@ -547,7 +557,7 @@ WHERE a.aggfnoid = p.oid AND
|
||||
a.aggtranstype != p2.prorettype OR
|
||||
a.aggtranstype != p2.proargtypes[0] OR
|
||||
NOT ((p2.pronargs = 2 AND p.proargtypes[0] = p2.proargtypes[1]) OR
|
||||
(p2.pronargs = 1 AND p.proargtypes[0] = 0)));
|
||||
(p2.pronargs = 1 AND p.proargtypes[0] = '"any"'::regtype)));
|
||||
aggfnoid | proname | oid | proname
|
||||
----------+---------+-----+-------------
|
||||
2121 | max | 768 | int4larger
|
||||
|
@ -74,7 +74,7 @@ create unique index PHone_name on PHone using btree (slotname bpchar_ops);
|
||||
-- * AFTER UPDATE on Room
|
||||
-- * - If room no changes let wall slots follow
|
||||
-- ************************************************************
|
||||
create function tg_room_au() returns opaque as '
|
||||
create function tg_room_au() returns trigger as '
|
||||
begin
|
||||
if new.roomno != old.roomno then
|
||||
update WSlot set roomno = new.roomno where roomno = old.roomno;
|
||||
@ -88,7 +88,7 @@ create trigger tg_room_au after update
|
||||
-- * AFTER DELETE on Room
|
||||
-- * - delete wall slots in this room
|
||||
-- ************************************************************
|
||||
create function tg_room_ad() returns opaque as '
|
||||
create function tg_room_ad() returns trigger as '
|
||||
begin
|
||||
delete from WSlot where roomno = old.roomno;
|
||||
return old;
|
||||
@ -100,7 +100,7 @@ create trigger tg_room_ad after delete
|
||||
-- * BEFORE INSERT or UPDATE on WSlot
|
||||
-- * - Check that room exists
|
||||
-- ************************************************************
|
||||
create function tg_wslot_biu() returns opaque as '
|
||||
create function tg_wslot_biu() returns trigger as '
|
||||
begin
|
||||
if count(*) = 0 from Room where roomno = new.roomno then
|
||||
raise exception ''Room % does not exist'', new.roomno;
|
||||
@ -114,7 +114,7 @@ create trigger tg_wslot_biu before insert or update
|
||||
-- * AFTER UPDATE on PField
|
||||
-- * - Let PSlots of this field follow
|
||||
-- ************************************************************
|
||||
create function tg_pfield_au() returns opaque as '
|
||||
create function tg_pfield_au() returns trigger as '
|
||||
begin
|
||||
if new.name != old.name then
|
||||
update PSlot set pfname = new.name where pfname = old.name;
|
||||
@ -128,7 +128,7 @@ create trigger tg_pfield_au after update
|
||||
-- * AFTER DELETE on PField
|
||||
-- * - Remove all slots of this patchfield
|
||||
-- ************************************************************
|
||||
create function tg_pfield_ad() returns opaque as '
|
||||
create function tg_pfield_ad() returns trigger as '
|
||||
begin
|
||||
delete from PSlot where pfname = old.name;
|
||||
return old;
|
||||
@ -140,7 +140,7 @@ create trigger tg_pfield_ad after delete
|
||||
-- * BEFORE INSERT or UPDATE on PSlot
|
||||
-- * - Ensure that our patchfield does exist
|
||||
-- ************************************************************
|
||||
create function tg_pslot_biu() returns opaque as '
|
||||
create function tg_pslot_biu() returns trigger as '
|
||||
declare
|
||||
pfrec record;
|
||||
rename new to ps;
|
||||
@ -158,7 +158,7 @@ create trigger tg_pslot_biu before insert or update
|
||||
-- * AFTER UPDATE on System
|
||||
-- * - If system name changes let interfaces follow
|
||||
-- ************************************************************
|
||||
create function tg_system_au() returns opaque as '
|
||||
create function tg_system_au() returns trigger as '
|
||||
begin
|
||||
if new.name != old.name then
|
||||
update IFace set sysname = new.name where sysname = old.name;
|
||||
@ -172,7 +172,7 @@ create trigger tg_system_au after update
|
||||
-- * BEFORE INSERT or UPDATE on IFace
|
||||
-- * - set the slotname to IF.sysname.ifname
|
||||
-- ************************************************************
|
||||
create function tg_iface_biu() returns opaque as '
|
||||
create function tg_iface_biu() returns trigger as '
|
||||
declare
|
||||
sname text;
|
||||
sysrec record;
|
||||
@ -197,7 +197,7 @@ create trigger tg_iface_biu before insert or update
|
||||
-- * AFTER INSERT or UPDATE or DELETE on Hub
|
||||
-- * - insert/delete/rename slots as required
|
||||
-- ************************************************************
|
||||
create function tg_hub_a() returns opaque as '
|
||||
create function tg_hub_a() returns trigger as '
|
||||
declare
|
||||
hname text;
|
||||
dummy integer;
|
||||
@ -250,7 +250,7 @@ end;
|
||||
-- * - prevent from manual manipulation
|
||||
-- * - set the slotname to HS.hubname.slotno
|
||||
-- ************************************************************
|
||||
create function tg_hslot_biu() returns opaque as '
|
||||
create function tg_hslot_biu() returns trigger as '
|
||||
declare
|
||||
sname text;
|
||||
xname HSlot.slotname%TYPE;
|
||||
@ -286,7 +286,7 @@ create trigger tg_hslot_biu before insert or update
|
||||
-- * BEFORE DELETE on HSlot
|
||||
-- * - prevent from manual manipulation
|
||||
-- ************************************************************
|
||||
create function tg_hslot_bd() returns opaque as '
|
||||
create function tg_hslot_bd() returns trigger as '
|
||||
declare
|
||||
hubrec record;
|
||||
begin
|
||||
@ -306,7 +306,7 @@ create trigger tg_hslot_bd before delete
|
||||
-- * BEFORE INSERT on all slots
|
||||
-- * - Check name prefix
|
||||
-- ************************************************************
|
||||
create function tg_chkslotname() returns opaque as '
|
||||
create function tg_chkslotname() returns trigger as '
|
||||
begin
|
||||
if substr(new.slotname, 1, 2) != tg_argv[0] then
|
||||
raise exception ''slotname must begin with %'', tg_argv[0];
|
||||
@ -328,7 +328,7 @@ create trigger tg_chkslotname before insert
|
||||
-- * BEFORE INSERT or UPDATE on all slots with slotlink
|
||||
-- * - Set slotlink to empty string if NULL value given
|
||||
-- ************************************************************
|
||||
create function tg_chkslotlink() returns opaque as '
|
||||
create function tg_chkslotlink() returns trigger as '
|
||||
begin
|
||||
if new.slotlink isnull then
|
||||
new.slotlink := '''';
|
||||
@ -350,7 +350,7 @@ create trigger tg_chkslotlink before insert or update
|
||||
-- * BEFORE INSERT or UPDATE on all slots with backlink
|
||||
-- * - Set backlink to empty string if NULL value given
|
||||
-- ************************************************************
|
||||
create function tg_chkbacklink() returns opaque as '
|
||||
create function tg_chkbacklink() returns trigger as '
|
||||
begin
|
||||
if new.backlink isnull then
|
||||
new.backlink := '''';
|
||||
@ -368,7 +368,7 @@ create trigger tg_chkbacklink before insert or update
|
||||
-- * BEFORE UPDATE on PSlot
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_pslot_bu() returns opaque as '
|
||||
create function tg_pslot_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from PSlot where slotname = old.slotname;
|
||||
@ -394,7 +394,7 @@ create trigger tg_pslot_bu before update
|
||||
-- * BEFORE UPDATE on WSlot
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_wslot_bu() returns opaque as '
|
||||
create function tg_wslot_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from WSlot where slotname = old.slotname;
|
||||
@ -420,7 +420,7 @@ create trigger tg_wslot_bu before update
|
||||
-- * BEFORE UPDATE on PLine
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_pline_bu() returns opaque as '
|
||||
create function tg_pline_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from PLine where slotname = old.slotname;
|
||||
@ -446,7 +446,7 @@ create trigger tg_pline_bu before update
|
||||
-- * BEFORE UPDATE on IFace
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_iface_bu() returns opaque as '
|
||||
create function tg_iface_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from IFace where slotname = old.slotname;
|
||||
@ -472,7 +472,7 @@ create trigger tg_iface_bu before update
|
||||
-- * BEFORE UPDATE on HSlot
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_hslot_bu() returns opaque as '
|
||||
create function tg_hslot_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname or new.hubname != old.hubname then
|
||||
delete from HSlot where slotname = old.slotname;
|
||||
@ -498,7 +498,7 @@ create trigger tg_hslot_bu before update
|
||||
-- * BEFORE UPDATE on PHone
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_phone_bu() returns opaque as '
|
||||
create function tg_phone_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from PHone where slotname = old.slotname;
|
||||
@ -522,7 +522,7 @@ create trigger tg_phone_bu before update
|
||||
-- * AFTER INSERT or UPDATE or DELETE on slot with backlink
|
||||
-- * - Ensure that the opponent correctly points back to us
|
||||
-- ************************************************************
|
||||
create function tg_backlink_a() returns opaque as '
|
||||
create function tg_backlink_a() returns trigger as '
|
||||
declare
|
||||
dummy integer;
|
||||
begin
|
||||
@ -666,7 +666,7 @@ end;
|
||||
-- * AFTER INSERT or UPDATE or DELETE on slot with slotlink
|
||||
-- * - Ensure that the opponent correctly points back to us
|
||||
-- ************************************************************
|
||||
create function tg_slotlink_a() returns opaque as '
|
||||
create function tg_slotlink_a() returns trigger as '
|
||||
declare
|
||||
dummy integer;
|
||||
begin
|
||||
|
@ -15,13 +15,12 @@
|
||||
-- Look for illegal values in pg_type fields.
|
||||
SELECT p1.oid, p1.typname
|
||||
FROM pg_type as p1
|
||||
WHERE (p1.typlen <= 0 AND p1.typlen != -1) OR
|
||||
p1.typtype not in('b', 'c', 'd', 'p') OR
|
||||
WHERE p1.typnamespace = 0 OR
|
||||
(p1.typlen <= 0 AND p1.typlen != -1) OR
|
||||
(p1.typtype not in ('b', 'c', 'd', 'p')) OR
|
||||
NOT p1.typisdefined OR
|
||||
(p1.typalign != 'c' AND p1.typalign != 's' AND
|
||||
p1.typalign != 'i' AND p1.typalign != 'd') OR
|
||||
(p1.typstorage != 'p' AND p1.typstorage != 'x' AND
|
||||
p1.typstorage != 'e' AND p1.typstorage != 'm');
|
||||
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
||||
(p1.typstorage not in ('p', 'x', 'e', 'm'));
|
||||
oid | typname
|
||||
-----+---------
|
||||
(0 rows)
|
||||
@ -91,27 +90,59 @@ WHERE p1.typtype != 'c' AND
|
||||
(0 rows)
|
||||
|
||||
-- Check for bogus typinput routines
|
||||
-- FIXME: ought to check prorettype, but there are special cases that make it
|
||||
-- hard: prorettype might be binary-compatible with the type but not the same,
|
||||
-- and for array types array_in's result has nothing to do with anything.
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype = 'b' AND
|
||||
(p2.pronargs != 1 OR p2.proretset) AND
|
||||
(p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
((p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring'::regtype) OR
|
||||
(p2.pronargs = 3 AND p2.proargtypes[0] = 'cstring'::regtype AND
|
||||
p2.proargtypes[1] = 'oid'::regtype AND
|
||||
p2.proargtypes[2] = 'int4'::regtype));
|
||||
oid | typname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- As of 7.3, this check finds SET and refcursor, which are borrowing
|
||||
-- other types' I/O routines
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
||||
(p2.prorettype = p1.oid AND NOT p2.proretset);
|
||||
oid | typname | oid | proname
|
||||
------+-----------+-----+-----------
|
||||
32 | SET | 109 | unknownin
|
||||
1790 | refcursor | 46 | textin
|
||||
(2 rows)
|
||||
|
||||
-- Varlena array types will point to array_in
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND
|
||||
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
||||
(p2.oid = 'array_in'::regproc);
|
||||
oid | typname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- Check for bogus typoutput routines
|
||||
-- The first OR subclause detects bogus non-array cases,
|
||||
-- the second one detects bogus array cases.
|
||||
-- FIXME: ought to check prorettype, but not clear what it should be.
|
||||
-- As of 7.3, this check finds SET and refcursor, which are borrowing
|
||||
-- other types' I/O routines
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typoutput = p2.oid AND p1.typtype = 'b' AND
|
||||
(p2.pronargs != 1 OR p2.proretset) AND
|
||||
(p2.pronargs != 2 OR p2.proretset OR p1.typelem = 0);
|
||||
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
((p2.pronargs = 1 AND p2.proargtypes[0] = p1.oid) OR
|
||||
(p2.oid = 'array_out'::regproc AND
|
||||
p1.typelem != 0));
|
||||
oid | typname | oid | proname
|
||||
------+-----------+-----+------------
|
||||
32 | SET | 110 | unknownout
|
||||
1790 | refcursor | 47 | textout
|
||||
(2 rows)
|
||||
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
(p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
||||
oid | typname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
@ -2,38 +2,48 @@
|
||||
-- CREATE_FUNCTION_1
|
||||
--
|
||||
|
||||
CREATE FUNCTION widget_in(opaque)
|
||||
CREATE FUNCTION widget_in(cstring)
|
||||
RETURNS widget
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
|
||||
CREATE FUNCTION widget_out(opaque)
|
||||
RETURNS opaque
|
||||
CREATE FUNCTION widget_out(widget)
|
||||
RETURNS cstring
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
|
||||
CREATE FUNCTION int44in(cstring)
|
||||
RETURNS city_budget
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
|
||||
CREATE FUNCTION int44out(city_budget)
|
||||
RETURNS cstring
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
|
||||
CREATE FUNCTION check_primary_key ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
|
||||
CREATE FUNCTION check_foreign_key ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
|
||||
CREATE FUNCTION autoinc ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/../../../contrib/spi/autoinc@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
|
||||
CREATE FUNCTION funny_dup17 ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
|
||||
CREATE FUNCTION ttdummy ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
|
||||
|
@ -1,33 +1,44 @@
|
||||
--
|
||||
-- CREATE_FUNCTION_1
|
||||
--
|
||||
CREATE FUNCTION widget_in(opaque)
|
||||
CREATE FUNCTION widget_in(cstring)
|
||||
RETURNS widget
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
WARNING: ProcedureCreate: type widget is not yet defined
|
||||
CREATE FUNCTION widget_out(opaque)
|
||||
RETURNS opaque
|
||||
CREATE FUNCTION widget_out(widget)
|
||||
RETURNS cstring
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
WARNING: Argument type "widget" is only a shell
|
||||
CREATE FUNCTION int44in(cstring)
|
||||
RETURNS city_budget
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
WARNING: ProcedureCreate: type city_budget is not yet defined
|
||||
CREATE FUNCTION int44out(city_budget)
|
||||
RETURNS cstring
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'c';
|
||||
WARNING: Argument type "city_budget" is only a shell
|
||||
CREATE FUNCTION check_primary_key ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
CREATE FUNCTION check_foreign_key ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
CREATE FUNCTION autoinc ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/../../../contrib/spi/autoinc@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
CREATE FUNCTION funny_dup17 ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
CREATE FUNCTION ttdummy ()
|
||||
RETURNS opaque
|
||||
RETURNS trigger
|
||||
AS '@abs_builddir@/regress@DLSUFFIX@'
|
||||
LANGUAGE 'C';
|
||||
CREATE FUNCTION set_ttdummy (int4)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.50 2002/03/06 06:10:50 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.51 2002/08/22 00:01:51 tgl Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
@ -26,6 +26,8 @@ extern Datum overpaid(PG_FUNCTION_ARGS);
|
||||
extern Datum boxarea(PG_FUNCTION_ARGS);
|
||||
extern char *reverse_name(char *string);
|
||||
extern int oldstyle_length(int n, text *t);
|
||||
extern Datum int44in(PG_FUNCTION_ARGS);
|
||||
extern Datum int44out(PG_FUNCTION_ARGS);
|
||||
|
||||
/*
|
||||
** Distance from a point to a path
|
||||
@ -684,3 +686,61 @@ set_ttdummy(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_INT32(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Type int44 has no real-world use, but the regression tests use it.
|
||||
* It's a four-element vector of int4's.
|
||||
*/
|
||||
|
||||
/*
|
||||
* int44in - converts "num num ..." to internal form
|
||||
*
|
||||
* Note: Fills any missing positions with zeroes.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(int44in);
|
||||
|
||||
Datum
|
||||
int44in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *input_string = PG_GETARG_CSTRING(0);
|
||||
int32 *result = (int32 *) palloc(4 * sizeof(int32));
|
||||
int i;
|
||||
|
||||
i = sscanf(input_string,
|
||||
"%d, %d, %d, %d",
|
||||
&result[0],
|
||||
&result[1],
|
||||
&result[2],
|
||||
&result[3]);
|
||||
while (i < 4)
|
||||
result[i++] = 0;
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* int44out - converts internal form to "num num ..."
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(int44out);
|
||||
|
||||
Datum
|
||||
int44out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 *an_array = (int32 *) PG_GETARG_POINTER(0);
|
||||
char *result = (char *) palloc(16 * 4); /* Allow 14 digits +
|
||||
* sign */
|
||||
int i;
|
||||
char *walk;
|
||||
|
||||
walk = result;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
pg_ltoa(an_array[i], walk);
|
||||
while (*++walk != '\0')
|
||||
;
|
||||
*walk++ = ' ';
|
||||
}
|
||||
*--walk = '\0';
|
||||
PG_RETURN_CSTRING(result);
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ CREATE TABLE x (
|
||||
e text
|
||||
);
|
||||
|
||||
CREATE FUNCTION fn_x_before () RETURNS OPAQUE AS '
|
||||
CREATE FUNCTION fn_x_before () RETURNS TRIGGER AS '
|
||||
BEGIN
|
||||
NEW.e := ''before trigger fired''::text;
|
||||
return NEW;
|
||||
END;
|
||||
' language 'plpgsql';
|
||||
|
||||
CREATE FUNCTION fn_x_after () RETURNS OPAQUE AS '
|
||||
CREATE FUNCTION fn_x_after () RETURNS TRIGGER AS '
|
||||
BEGIN
|
||||
UPDATE x set e=''after trigger fired'' where c=''stuff'';
|
||||
return NULL;
|
||||
|
@ -18,10 +18,28 @@ CREATE TYPE city_budget (
|
||||
|
||||
-- Test type-related default values (broken in releases before PG 7.2)
|
||||
|
||||
-- Make dummy I/O routines using the existing internal support for int4, text
|
||||
CREATE FUNCTION int42_in(cstring)
|
||||
RETURNS int42
|
||||
AS 'int4in'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
CREATE FUNCTION int42_out(int42)
|
||||
RETURNS cstring
|
||||
AS 'int4out'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
CREATE FUNCTION text_w_default_in(cstring)
|
||||
RETURNS text_w_default
|
||||
AS 'textin'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
CREATE FUNCTION text_w_default_out(text_w_default)
|
||||
RETURNS cstring
|
||||
AS 'textout'
|
||||
LANGUAGE 'internal' WITH (isStrict);
|
||||
|
||||
CREATE TYPE int42 (
|
||||
internallength = 4,
|
||||
input = int4in,
|
||||
output = int4out,
|
||||
input = int42_in,
|
||||
output = int42_out,
|
||||
alignment = int4,
|
||||
default = 42,
|
||||
passedbyvalue
|
||||
@ -29,8 +47,8 @@ CREATE TYPE int42 (
|
||||
|
||||
CREATE TYPE text_w_default (
|
||||
internallength = variable,
|
||||
input = textin,
|
||||
output = textout,
|
||||
input = text_w_default_in,
|
||||
output = text_w_default_out,
|
||||
alignment = int4,
|
||||
default = 'zippo'
|
||||
);
|
||||
|
@ -24,9 +24,9 @@ DROP FUNCTION equipment(hobbies_r);
|
||||
|
||||
DROP FUNCTION user_relns();
|
||||
|
||||
DROP FUNCTION widget_in(opaque);
|
||||
DROP FUNCTION widget_in(cstring);
|
||||
|
||||
DROP FUNCTION widget_out(opaque);
|
||||
DROP FUNCTION widget_out(widget);
|
||||
|
||||
DROP FUNCTION pt_in_widget(point,widget);
|
||||
|
||||
|
@ -18,17 +18,24 @@
|
||||
-- **************** pg_proc ****************
|
||||
|
||||
-- Look for illegal values in pg_proc fields.
|
||||
-- NOTE: currently there are a few pg_proc entries that have prorettype = 0.
|
||||
-- Someday that ought to be cleaned up.
|
||||
-- NOTE: in reality pronargs could be more than 10, but I'm too lazy to put
|
||||
-- a larger number of proargtypes check clauses in here. If we ever have
|
||||
-- more-than-10-arg functions in the standard catalogs, extend this query.
|
||||
|
||||
SELECT p1.oid, p1.proname
|
||||
FROM pg_proc as p1
|
||||
WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR
|
||||
p1.pronargs < 0 OR p1.pronargs > 16)
|
||||
AND p1.proname !~ '^pl[^_]+_call_handler$'
|
||||
AND p1.proname !~ '^RI_FKey_'
|
||||
AND p1.proname !~ 'costestimate$'
|
||||
AND p1.proname != 'update_pg_pwd_and_pg_group';
|
||||
WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
||||
p1.pronargs < 0 OR p1.pronargs > 10 OR
|
||||
(p1.proargtypes[0] = 0 AND p1.pronargs > 0) OR
|
||||
(p1.proargtypes[1] = 0 AND p1.pronargs > 1) OR
|
||||
(p1.proargtypes[2] = 0 AND p1.pronargs > 2) OR
|
||||
(p1.proargtypes[3] = 0 AND p1.pronargs > 3) OR
|
||||
(p1.proargtypes[4] = 0 AND p1.pronargs > 4) OR
|
||||
(p1.proargtypes[5] = 0 AND p1.pronargs > 5) OR
|
||||
(p1.proargtypes[6] = 0 AND p1.pronargs > 6) OR
|
||||
(p1.proargtypes[7] = 0 AND p1.pronargs > 7) OR
|
||||
(p1.proargtypes[8] = 0 AND p1.pronargs > 8) OR
|
||||
(p1.proargtypes[9] = 0 AND p1.pronargs > 9);
|
||||
|
||||
-- Look for conflicting proc definitions (same names and input datatypes).
|
||||
-- (This test should be dead code now that we have the unique index
|
||||
@ -174,7 +181,7 @@ WHERE c.castfunc = 0 AND NOT c.castimplicit;
|
||||
SELECT *
|
||||
FROM pg_cast c
|
||||
WHERE c.castfunc = 0 AND
|
||||
NOT EXISTS (SELECT * FROM pg_cast k
|
||||
NOT EXISTS (SELECT 1 FROM pg_cast k
|
||||
WHERE k.castfunc = 0 AND
|
||||
k.castsource = c.casttarget AND
|
||||
k.casttarget = c.castsource);
|
||||
@ -279,7 +286,7 @@ WHERE p1.oprlsortop != 0 AND
|
||||
|
||||
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
|
||||
WHERE p1.oprlsortop != 0 AND NOT
|
||||
EXISTS(SELECT * FROM pg_operator AS p2 WHERE
|
||||
EXISTS(SELECT 1 FROM pg_operator AS p2 WHERE
|
||||
p2.oprname = '<' AND
|
||||
p2.oprleft = p1.oprleft AND
|
||||
p2.oprright = p1.oprright AND
|
||||
@ -287,7 +294,7 @@ WHERE p1.oprlsortop != 0 AND NOT
|
||||
|
||||
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
|
||||
WHERE p1.oprlsortop != 0 AND NOT
|
||||
EXISTS(SELECT * FROM pg_operator AS p2 WHERE
|
||||
EXISTS(SELECT 1 FROM pg_operator AS p2 WHERE
|
||||
p2.oprname = '>' AND
|
||||
p2.oprleft = p1.oprleft AND
|
||||
p2.oprright = p1.oprright AND
|
||||
@ -386,7 +393,7 @@ WHERE p1.oprcode = p2.oid AND
|
||||
-- If oprrest is set, the operator must return boolean,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a restriction selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque, int4)
|
||||
-- The proc signature we want is: float8 proc(internal, oid, internal, int4)
|
||||
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
@ -394,13 +401,15 @@ WHERE p1.oprrest = p2.oid AND
|
||||
(p1.oprresult != 'bool'::regtype OR
|
||||
p2.prorettype != 'float8'::regtype OR p2.proretset OR
|
||||
p2.pronargs != 4 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 'int4'::regtype);
|
||||
p2.proargtypes[0] != 'internal'::regtype OR
|
||||
p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 'internal'::regtype OR
|
||||
p2.proargtypes[3] != 'int4'::regtype);
|
||||
|
||||
-- If oprjoin is set, the operator must be a binary boolean op,
|
||||
-- and it must link to a proc with the right signature
|
||||
-- to be a join selectivity estimator.
|
||||
-- The proc signature we want is: float8 proc(opaque, oid, opaque)
|
||||
-- The proc signature we want is: float8 proc(internal, oid, internal)
|
||||
|
||||
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
||||
FROM pg_operator AS p1, pg_proc AS p2
|
||||
@ -408,8 +417,9 @@ WHERE p1.oprjoin = p2.oid AND
|
||||
(p1.oprkind != 'b' OR p1.oprresult != 'bool'::regtype OR
|
||||
p2.prorettype != 'float8'::regtype OR p2.proretset OR
|
||||
p2.pronargs != 3 OR
|
||||
p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 0);
|
||||
p2.proargtypes[0] != 'internal'::regtype OR
|
||||
p2.proargtypes[1] != 'oid'::regtype OR
|
||||
p2.proargtypes[2] != 'internal'::regtype);
|
||||
|
||||
-- **************** pg_aggregate ****************
|
||||
|
||||
@ -454,7 +464,7 @@ WHERE a.aggfnoid = p.oid AND
|
||||
a.aggtranstype != p2.prorettype OR
|
||||
a.aggtranstype != p2.proargtypes[0] OR
|
||||
NOT ((p2.pronargs = 2 AND p.proargtypes[0] = p2.proargtypes[1]) OR
|
||||
(p2.pronargs = 1 AND p.proargtypes[0] = 0)));
|
||||
(p2.pronargs = 1 AND p.proargtypes[0] = '"any"'::regtype)));
|
||||
|
||||
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
||||
-- FIXME: what about binary-compatible types?
|
||||
|
@ -107,7 +107,7 @@ create unique index PHone_name on PHone using btree (slotname bpchar_ops);
|
||||
-- * AFTER UPDATE on Room
|
||||
-- * - If room no changes let wall slots follow
|
||||
-- ************************************************************
|
||||
create function tg_room_au() returns opaque as '
|
||||
create function tg_room_au() returns trigger as '
|
||||
begin
|
||||
if new.roomno != old.roomno then
|
||||
update WSlot set roomno = new.roomno where roomno = old.roomno;
|
||||
@ -124,7 +124,7 @@ create trigger tg_room_au after update
|
||||
-- * AFTER DELETE on Room
|
||||
-- * - delete wall slots in this room
|
||||
-- ************************************************************
|
||||
create function tg_room_ad() returns opaque as '
|
||||
create function tg_room_ad() returns trigger as '
|
||||
begin
|
||||
delete from WSlot where roomno = old.roomno;
|
||||
return old;
|
||||
@ -139,7 +139,7 @@ create trigger tg_room_ad after delete
|
||||
-- * BEFORE INSERT or UPDATE on WSlot
|
||||
-- * - Check that room exists
|
||||
-- ************************************************************
|
||||
create function tg_wslot_biu() returns opaque as '
|
||||
create function tg_wslot_biu() returns trigger as '
|
||||
begin
|
||||
if count(*) = 0 from Room where roomno = new.roomno then
|
||||
raise exception ''Room % does not exist'', new.roomno;
|
||||
@ -156,7 +156,7 @@ create trigger tg_wslot_biu before insert or update
|
||||
-- * AFTER UPDATE on PField
|
||||
-- * - Let PSlots of this field follow
|
||||
-- ************************************************************
|
||||
create function tg_pfield_au() returns opaque as '
|
||||
create function tg_pfield_au() returns trigger as '
|
||||
begin
|
||||
if new.name != old.name then
|
||||
update PSlot set pfname = new.name where pfname = old.name;
|
||||
@ -173,7 +173,7 @@ create trigger tg_pfield_au after update
|
||||
-- * AFTER DELETE on PField
|
||||
-- * - Remove all slots of this patchfield
|
||||
-- ************************************************************
|
||||
create function tg_pfield_ad() returns opaque as '
|
||||
create function tg_pfield_ad() returns trigger as '
|
||||
begin
|
||||
delete from PSlot where pfname = old.name;
|
||||
return old;
|
||||
@ -188,7 +188,7 @@ create trigger tg_pfield_ad after delete
|
||||
-- * BEFORE INSERT or UPDATE on PSlot
|
||||
-- * - Ensure that our patchfield does exist
|
||||
-- ************************************************************
|
||||
create function tg_pslot_biu() returns opaque as '
|
||||
create function tg_pslot_biu() returns trigger as '
|
||||
declare
|
||||
pfrec record;
|
||||
rename new to ps;
|
||||
@ -209,7 +209,7 @@ create trigger tg_pslot_biu before insert or update
|
||||
-- * AFTER UPDATE on System
|
||||
-- * - If system name changes let interfaces follow
|
||||
-- ************************************************************
|
||||
create function tg_system_au() returns opaque as '
|
||||
create function tg_system_au() returns trigger as '
|
||||
begin
|
||||
if new.name != old.name then
|
||||
update IFace set sysname = new.name where sysname = old.name;
|
||||
@ -226,7 +226,7 @@ create trigger tg_system_au after update
|
||||
-- * BEFORE INSERT or UPDATE on IFace
|
||||
-- * - set the slotname to IF.sysname.ifname
|
||||
-- ************************************************************
|
||||
create function tg_iface_biu() returns opaque as '
|
||||
create function tg_iface_biu() returns trigger as '
|
||||
declare
|
||||
sname text;
|
||||
sysrec record;
|
||||
@ -254,7 +254,7 @@ create trigger tg_iface_biu before insert or update
|
||||
-- * AFTER INSERT or UPDATE or DELETE on Hub
|
||||
-- * - insert/delete/rename slots as required
|
||||
-- ************************************************************
|
||||
create function tg_hub_a() returns opaque as '
|
||||
create function tg_hub_a() returns trigger as '
|
||||
declare
|
||||
hname text;
|
||||
dummy integer;
|
||||
@ -312,7 +312,7 @@ end;
|
||||
-- * - prevent from manual manipulation
|
||||
-- * - set the slotname to HS.hubname.slotno
|
||||
-- ************************************************************
|
||||
create function tg_hslot_biu() returns opaque as '
|
||||
create function tg_hslot_biu() returns trigger as '
|
||||
declare
|
||||
sname text;
|
||||
xname HSlot.slotname%TYPE;
|
||||
@ -351,7 +351,7 @@ create trigger tg_hslot_biu before insert or update
|
||||
-- * BEFORE DELETE on HSlot
|
||||
-- * - prevent from manual manipulation
|
||||
-- ************************************************************
|
||||
create function tg_hslot_bd() returns opaque as '
|
||||
create function tg_hslot_bd() returns trigger as '
|
||||
declare
|
||||
hubrec record;
|
||||
begin
|
||||
@ -374,7 +374,7 @@ create trigger tg_hslot_bd before delete
|
||||
-- * BEFORE INSERT on all slots
|
||||
-- * - Check name prefix
|
||||
-- ************************************************************
|
||||
create function tg_chkslotname() returns opaque as '
|
||||
create function tg_chkslotname() returns trigger as '
|
||||
begin
|
||||
if substr(new.slotname, 1, 2) != tg_argv[0] then
|
||||
raise exception ''slotname must begin with %'', tg_argv[0];
|
||||
@ -403,7 +403,7 @@ create trigger tg_chkslotname before insert
|
||||
-- * BEFORE INSERT or UPDATE on all slots with slotlink
|
||||
-- * - Set slotlink to empty string if NULL value given
|
||||
-- ************************************************************
|
||||
create function tg_chkslotlink() returns opaque as '
|
||||
create function tg_chkslotlink() returns trigger as '
|
||||
begin
|
||||
if new.slotlink isnull then
|
||||
new.slotlink := '''';
|
||||
@ -432,7 +432,7 @@ create trigger tg_chkslotlink before insert or update
|
||||
-- * BEFORE INSERT or UPDATE on all slots with backlink
|
||||
-- * - Set backlink to empty string if NULL value given
|
||||
-- ************************************************************
|
||||
create function tg_chkbacklink() returns opaque as '
|
||||
create function tg_chkbacklink() returns trigger as '
|
||||
begin
|
||||
if new.backlink isnull then
|
||||
new.backlink := '''';
|
||||
@ -455,7 +455,7 @@ create trigger tg_chkbacklink before insert or update
|
||||
-- * BEFORE UPDATE on PSlot
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_pslot_bu() returns opaque as '
|
||||
create function tg_pslot_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from PSlot where slotname = old.slotname;
|
||||
@ -484,7 +484,7 @@ create trigger tg_pslot_bu before update
|
||||
-- * BEFORE UPDATE on WSlot
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_wslot_bu() returns opaque as '
|
||||
create function tg_wslot_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from WSlot where slotname = old.slotname;
|
||||
@ -513,7 +513,7 @@ create trigger tg_wslot_bu before update
|
||||
-- * BEFORE UPDATE on PLine
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_pline_bu() returns opaque as '
|
||||
create function tg_pline_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from PLine where slotname = old.slotname;
|
||||
@ -542,7 +542,7 @@ create trigger tg_pline_bu before update
|
||||
-- * BEFORE UPDATE on IFace
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_iface_bu() returns opaque as '
|
||||
create function tg_iface_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from IFace where slotname = old.slotname;
|
||||
@ -571,7 +571,7 @@ create trigger tg_iface_bu before update
|
||||
-- * BEFORE UPDATE on HSlot
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_hslot_bu() returns opaque as '
|
||||
create function tg_hslot_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname or new.hubname != old.hubname then
|
||||
delete from HSlot where slotname = old.slotname;
|
||||
@ -600,7 +600,7 @@ create trigger tg_hslot_bu before update
|
||||
-- * BEFORE UPDATE on PHone
|
||||
-- * - do delete/insert instead of update if name changes
|
||||
-- ************************************************************
|
||||
create function tg_phone_bu() returns opaque as '
|
||||
create function tg_phone_bu() returns trigger as '
|
||||
begin
|
||||
if new.slotname != old.slotname then
|
||||
delete from PHone where slotname = old.slotname;
|
||||
@ -627,7 +627,7 @@ create trigger tg_phone_bu before update
|
||||
-- * AFTER INSERT or UPDATE or DELETE on slot with backlink
|
||||
-- * - Ensure that the opponent correctly points back to us
|
||||
-- ************************************************************
|
||||
create function tg_backlink_a() returns opaque as '
|
||||
create function tg_backlink_a() returns trigger as '
|
||||
declare
|
||||
dummy integer;
|
||||
begin
|
||||
@ -781,7 +781,7 @@ end;
|
||||
-- * AFTER INSERT or UPDATE or DELETE on slot with slotlink
|
||||
-- * - Ensure that the opponent correctly points back to us
|
||||
-- ************************************************************
|
||||
create function tg_slotlink_a() returns opaque as '
|
||||
create function tg_slotlink_a() returns trigger as '
|
||||
declare
|
||||
dummy integer;
|
||||
begin
|
||||
|
@ -18,13 +18,12 @@
|
||||
|
||||
SELECT p1.oid, p1.typname
|
||||
FROM pg_type as p1
|
||||
WHERE (p1.typlen <= 0 AND p1.typlen != -1) OR
|
||||
p1.typtype not in('b', 'c', 'd', 'p') OR
|
||||
WHERE p1.typnamespace = 0 OR
|
||||
(p1.typlen <= 0 AND p1.typlen != -1) OR
|
||||
(p1.typtype not in ('b', 'c', 'd', 'p')) OR
|
||||
NOT p1.typisdefined OR
|
||||
(p1.typalign != 'c' AND p1.typalign != 's' AND
|
||||
p1.typalign != 'i' AND p1.typalign != 'd') OR
|
||||
(p1.typstorage != 'p' AND p1.typstorage != 'x' AND
|
||||
p1.typstorage != 'e' AND p1.typstorage != 'm');
|
||||
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
||||
(p1.typstorage not in ('p', 'x', 'e', 'm'));
|
||||
|
||||
-- Look for "pass by value" types that can't be passed by value.
|
||||
|
||||
@ -76,26 +75,45 @@ WHERE p1.typtype != 'c' AND
|
||||
(p1.typinput = 0 OR p1.typoutput = 0);
|
||||
|
||||
-- Check for bogus typinput routines
|
||||
-- FIXME: ought to check prorettype, but there are special cases that make it
|
||||
-- hard: prorettype might be binary-compatible with the type but not the same,
|
||||
-- and for array types array_in's result has nothing to do with anything.
|
||||
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype = 'b' AND
|
||||
(p2.pronargs != 1 OR p2.proretset) AND
|
||||
(p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
((p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring'::regtype) OR
|
||||
(p2.pronargs = 3 AND p2.proargtypes[0] = 'cstring'::regtype AND
|
||||
p2.proargtypes[1] = 'oid'::regtype AND
|
||||
p2.proargtypes[2] = 'int4'::regtype));
|
||||
|
||||
-- As of 7.3, this check finds SET and refcursor, which are borrowing
|
||||
-- other types' I/O routines
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
||||
(p2.prorettype = p1.oid AND NOT p2.proretset);
|
||||
|
||||
-- Varlena array types will point to array_in
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND
|
||||
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
||||
(p2.oid = 'array_in'::regproc);
|
||||
|
||||
-- Check for bogus typoutput routines
|
||||
-- The first OR subclause detects bogus non-array cases,
|
||||
-- the second one detects bogus array cases.
|
||||
-- FIXME: ought to check prorettype, but not clear what it should be.
|
||||
|
||||
-- As of 7.3, this check finds SET and refcursor, which are borrowing
|
||||
-- other types' I/O routines
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
((p2.pronargs = 1 AND p2.proargtypes[0] = p1.oid) OR
|
||||
(p2.oid = 'array_out'::regproc AND
|
||||
p1.typelem != 0));
|
||||
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typoutput = p2.oid AND p1.typtype = 'b' AND
|
||||
(p2.pronargs != 1 OR p2.proretset) AND
|
||||
(p2.pronargs != 2 OR p2.proretset OR p1.typelem = 0);
|
||||
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
(p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
||||
|
||||
-- **************** pg_class ****************
|
||||
|
||||
|
Reference in New Issue
Block a user