(Sorry for my bad english comments)
Demo sql:

BEGIN; -- Begins the magic
CREATE TABLE pk ( -- pk table
    id BIGINT,
    CONSTRAINT pk2_id PRIMARY KEY (id)
);

CREATE TABLE fk ( -- fk table
    fk_ids BIGINT[]
);

CREATE FUNCTION bia2bi(bigint[]) RETURNS bigint -- temp type cast
    AS $$
SELECT $1[array_lower($1, 1)];
$$
LANGUAGE sql;

CREATE FUNCTION bi_fk(bigint, bigint[]) RETURNS boolean --FK FUNCTION FOR
TABLE pk
    AS $$
    BEGIN
    IF (SELECT count(*) FROM pk WHERE id = ANY($2)) = (array_upper($2, 1) -
array_lower($2, 1) + 1) THEN
    RETURN TRUE;
    END IF;
    RAISE EXCEPTION 'NO FK![%, %]', $1, $2; -- RAISE ERROR MSG, and dont
scan other million records
END;
$$
LANGUAGE 'plpgsql';

CREATE OPERATOR ==> ( -- Cutsom operator for calling bi_fk
    PROCEDURE = bi_fk,
    LEFTARG = bigint,
    RIGHTARG = bigint[]);

CREATE CAST (bigint[] AS bigint) -- TEMP CAST FOR INDEX CREATION
    WITH FUNCTION bia2bi(bigint[])
    AS IMPLICIT;

ALTER TABLE "fk" -- CREATE FK
  ADD CONSTRAINT "fk_id" FOREIGN KEY ("fk_ids")
    REFERENCES "pk"("id")
    ON DELETE NO ACTION
    ON UPDATE NO ACTION
    NOT DEFERRABLE;
DROP CAST(bigint[] AS bigint); -- REMOVE CAST(recomended, but not needed)

UPDATE pg_constraint
    SET conpfeqop = ARRAY(SELECT OID FROM pg_operator WHERE oprname = '==>')
        WHERE conname = 'fk_id'; -- CHANGING COMPARE FUNCTION


INSERT INTO pk SELECT k FROM GENERATE_series(1, 100000) as k; -- MAKE DATA

INSERT INTO fk VALUES(ARRAY[1,2, 3]); -- TESTING
INSERT INTO fk VALUES(ARRAY[6,3,5]); -- TESTING
INSERT INTO fk VALUES(ARRAY[6,3,444444444444444445]); -- FK BREAK.
ROLLBACK; -- Magic rollback =)

Reply via email to