Does a 'DISABLE TRIGGER ALL' also disable DOMAIN checks in Postgres? - postgresql

I'd like just to confirm if the 'ALTER TABLE table_name DISABLE TRIGGER ALL' also disables DOMAIN checks in Postgres?

No, DOMAIN and CHECK constraints are not disabled.
Only some constraints are implemented as triggers in Postgres. The most notable would be a trigger on the "parent" table in the FK constraint, and triggers on deferrable unique / exclusion constraints. These require some complicated logic that cannot be checked against a single row and were, consequently, implemented as triggers.
DOMAIN checks are entirely "internal", the checks cannot use subqueries, and by all means operate like CHECK constraints. There should be no triggers.
You could check pg_trigger to see if your target table has any "internally defined' triggers.

Related

Postgres: DISABLE TRIGGER ALL and ON UPDATE CASCADE

It seems like when I
ALTER TABLE foo DISABLE TRIGGER ALL;
DELETE FROM foo;
The deletions don't get cascaded to other tables with
FOREIGN KEY ("fooId") REFERENCES "foo"("id") ON DELETE CASCADE
constraints, but I can't find anything in the documentation about this.
I also don't see any triggers I didn't create in
SELECT * FROM information_schema.triggers;
I'm guessing ON UPDATE/ON DELETE are implemented internally as triggers (which aren't visible in pgAdmin)? Does anyone know where this is documented?
Try here:
DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER
These forms configure the firing of trigger(s) belonging to the table. A disabled trigger is still known to the system, but is not executed when its triggering event occurs. For a deferred trigger, the enable status is checked when the event occurs, not when the trigger function is actually executed. One can disable or enable a single trigger specified by name, or all triggers on the table, or only user triggers (this option excludes internally generated constraint triggers such as those that are used to implement foreign key constraints or deferrable uniqueness and exclusion constraints). Disabling or enabling internally generated constraint triggers requires superuser privileges; it should be done with caution since of course the integrity of the constraint cannot be guaranteed if the triggers are not executed.

Disable all constraints besides uniques

What is the query to disable all constraints like foreign keys, primary keys but leave uniques?
PostgreSQL does not allow to disable constraints generally speaking. You can only disable foreign key constraints by disabling the related trigger used to implement the foreign keys.
See https://www.postgresql.org/docs/12/sql-altertable.html#SQL-ALTERTABLE-NOTES
DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER
One can disable or enable a single trigger specified by name, or all
triggers on the table, or only user triggers (this option excludes
internally generated constraint triggers such as those that are used
to implement foreign key constraints or deferrable uniqueness and
exclusion constraints). Disabling or enabling internally generated
constraint triggers requires superuser privileges; it should be done
with caution since of course the integrity of the constraint cannot be
guaranteed if the triggers are not executed.

equivalent for enable and disable validate and novalidate in db2

I want to enable constraint but don't validate existing record. only validate future record in db2.
This should be apply for check constraint.
alter table table_name add check (column_name <> '')
DB2 hast the ENFORCED and NOT ENFORCED options for check constraints. The syntax for constraints is part of the CREATE TABLE and ALTER TABLE statements. A sub-option is to either set TRUSTED or NOT TRUSTED depending on the quality of your data.
Something like the following should work:
alter table mytable add check (column1>myvalue) not enforced trusted
try Something like this
ALTER TABLE YOURLIB.YOURTABLE DROP CONSTRAINT YOURLIB.YOURCONSTRAINTNAME1;
ALTER TABLE YOURLIB.YOURTABLE ADD CONSTRAINT YOURLIB.YOURCONSTRAINTNAME1 CHECK (YOUCOLUMNNAME<>'') NOT ENFORCED TRUSTED;

Is pg_class.relhastriggers a safe alternative to `ALTER TABLE ... DISABLE TRIGGER USER`?

On my table I have a trigger which prevents updates, therefore meaning that rows are effectively immutable post insertion.
When needing to perform retrospective updates to this table (e.g. adding a new calculated field) I have taken the following approach:
ALTER TABLE my_table DISABLE TRIGGER USER;
UPDATE my_table
SET x = (...);
ALTER TABLE my_table ENABLE TRIGGER USER;
The downside to this approach is that it requires an AccessExclusiveLock.
I was wondering if the following is safe for me to use given it is guaranteed that the rows in the UPDATE will not be being updated by other queries:
BEGIN;
UPDATE pg_class
SET relhastriggers = FALSE
WHERE relname = 'my_table';
UPDATE my_table
SET x = (...);
UPDATE pg_class
SET relhastriggers = TRUE
WHERE relname = 'my_table';
COMMIT;
What I have tried so far suggests this is safe and that outside of this transaction the triggers will continue to be applied as normal.
Also, if it is indeed safe for my use case what are the circumstances in which it would not be safe?
I am using Postgres 9.4.8.
Thanks :-)
Updating relhastriggers will behave more like DISABLE TRIGGER ALL, i.e. it will also disable the internal triggers used for foreign key and deferred uniqueness checks. This may or may not be an issue in your case.
I don't know if a direct update of pg_class might violate some assumption made in some corner of the Postgres codebase. But in general, hacking catalog tables is inherently unsafe; even if it doesn't break anything now, there is no guarantee that this will be the case in future versions.
REVOKE UPDATE ON my_table is a far better approach for blocking updates. Superusers are automatically exempt, so anybody with permission to UPDATE pg_class will have no problem with my_table.
If, for whatever reason, you really do need to do this with a trigger, there is another (somewhat hacky, but at least supported) way of circumventing it. By default, triggers will not be fired by replication processes (though this can be controlled via the ENABLE ALWAYS clause of ALTER TABLE). This means that you can bypass the trigger by impersonating a replicator:
BEGIN;
SET LOCAL session_replication_role TO replica;
UPDATE my_table SET x = (...);
COMMIT;
As with the catalog update, this will also disable any internal constraint triggers.

PostgreSQL - disabling constraints

I have a table with approx 5 million rows which has a fk constraint referencing the primary key of another table (also approx 5 million rows).
I need to delete about 75000 rows from both tables. I know that if I try doing this with the fk constraint enabled it's going to take an unacceptable amount of time.
Coming from an Oracle background my first thought was to disable the constraint, do the delete & then reenable the constraint. PostGres appears to let me disable constraint triggers if I am a super user (I'm not, but I am logging in as the user that owns/created the objects) but that doesn't seem to be quite what I want.
The other option is to drop the constraint and then reinstate it. I'm worried that rebuilding the constraint is going to take ages given the size of my tables.
Any thoughts?
edit: after Billy's encouragement I've tried doing the delete without changing any constraints and it takes in excess of 10 minutes. However, I have discovered that the table from which I'm trying to delete has a self referential foreign key ... duplicated (& non indexed).
Final update - I dropped the self referential foreign key, did my delete and added it back in. Billy's right all round but unfortunately I can't accept his comment as the answer!
Per previous comments, it should be a problem. That said, there is a command that may be what you're looking to - it'll set the constraints to deferred so they're checked on COMMIT, not on every delete. If you're doing just one big DELETE of all the rows, it won't make a difference, but if you're doing it in pieces, it will.
SET CONSTRAINTS ALL DEFERRED
is what you are looking for in that case. Note that constraints must be marked as DEFERRABLE before they can be deferred. For example:
ALTER TABLE table_name
ADD CONSTRAINT constraint_uk UNIQUE(column_1, column_2)
DEFERRABLE INITIALLY IMMEDIATE;
The constraint can then be deferred in a transaction or function as follows:
CREATE OR REPLACE FUNCTION f() RETURNS void AS
$BODY$
BEGIN
SET CONSTRAINTS ALL DEFERRED;
-- Code that temporarily violates the constraint...
-- UPDATE table_name ...
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
What worked for me was to disable one by one the TRIGGERS of those tables that are gonna be involved in the DELETE operation.
ALTER TABLE reference DISABLE TRIGGER ALL;
DELETE FROM reference WHERE refered_id > 1;
ALTER TABLE reference ENABLE TRIGGER ALL;
Solution is working in version 9.3.16. In my case time went from 45 minutes to 14 seconds executing DELETE operations.
As stated in the comments section by #amphetamachine, you will need to have admin privileges to the tables to perform this task.
If you try DISABLE TRIGGER ALL and get an error like permission denied: "RI_ConstraintTrigger_a_16428" is a system trigger (I got this on Amazon RDS), try this:
set session_replication_role to replica;
If this succeeds, all triggers that underlie table constraints will be disabled. Now it's up to you to make sure your changes leave the DB in a consistent state!
Then when you are done, reenable triggers & constraints for your session with:
set session_replication_role to default;
(This answer assumes your intent is to delete all of the rows of these tables, not just a selection.)
I also had to do this, but as part of a test suite. I found the answer, suggested elsewhere on SO. Use TRUNCATE TABLE as follows:
TRUNCATE TABLE <list-of-table-names> [RESTART IDENTITY] [CASCADE];
The following quickly deletes all rows from tables table1, table2, and table3, provided that there are no references to rows of these tables from tables not listed:
TRUNCATE TABLE table1, table2, table3;
As long as references are between the tables listed, PostgreSQL will delete all the rows without concern for referential integrity. If a table other than those listed references a row of one of these tables, the query will fail.
However, you can qualify the query so that it also truncates all tables with references to the listed tables (although I have not tried this):
TRUNCATE TABLE table1, table2, table3 CASCADE;
By default, the sequences of these tables do not restart numbering. New rows will continue with the next number of the sequence. To restart sequence numbering:
TRUNCATE TABLE table1, table2, table3 RESTART IDENTITY;
My PostgreSQL is 9.6.8.
set session_replication_role to replica;
work for me but I need permission.
I login psql with super user.
sudo -u postgres psql
Then connect to my database
\c myDB
And run:
set session_replication_role to replica;
Now I can delete from table with constraint.
Disable all table constraints
ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName
-- Enable all table constraints
ALTER TABLE TableName CHECK CONSTRAINT ConstraintName