CREATE LANGUAGE plperlu; \set ECHO none \i deny_updates.sql \set ECHO all CREATE TEMP TABLE test_users(id INTEGER PRIMARY KEY, name VARCHAR, password VARCHAR(32), enabled BOOLEAN); -- Disallow update of name field -- CREATE TRIGGER deny_test_users_update BEFORE UPDATE ON test_users FOR EACH ROW EXECUTE PROCEDURE deny_updates('', name); INSERT INTO test_users VALUES(1, 'alexk', 'iddqd', true); INSERT INTO test_users VALUES(2, 'alexk', 'idkfa', true); INSERT INTO test_users VALUES(3, 'alexk', 'idspispopd', false); -- Should be executed -- UPDATE test_users SET password='idclip' WHERE password='idspispopd'; UPDATE test_users SET enabled=false WHERE id=1; UPDATE test_users SET id=id*10; -- Should be cancelled -- UPDATE test_users SET name='devrim' WHERE name='alexk'; -- Disallow updates of 'enabled' field -- CREATE TRIGGER deny_test_users_update_most BEFORE UPDATE ON test_users FOR EACH ROW EXECUTE PROCEDURE deny_updates('', enabled); -- Try to update id, should be allowed --- UPDATE test_users SET id=id-1; UPDATE test_users SET password='bestkeptsecret' WHERE name='alexk'; -- Try to update some other fields, should fail -- UPDATE test_users SET name='jd' WHERE enabled=true; UPDATE test_users SET enabled=false; -- Drop all triggers --- DROP TRIGGER deny_test_users_update on test_users; DROP TRIGGER deny_test_users_update_most on test_users; -- Check the result --- SELECT * from test_users; -- Check that now can update fields --- UPDATE test_users SET id=id-1; UPDATE test_users SET name='andrei' WHERE id IN (SELECT id FROM test_users LIMIT 1); -- Create trigger on multiple columns. Enable updates for 'name' and 'passsword' -- CREATE TRIGGER deny_test_users_multi BEFORE UPDATE ON test_users FOR EACH ROW EXECUTE PROCEDURE deny_updates('', id, enabled); -- The following updates should fail -- UPDATE test_users SET id=101, enabled=false WHERE name='alexk'; UPDATE test_users SET enabled=true; -- Drop all triggers -- DROP TRIGGER deny_test_users_multi on test_users; -- Create trigger which disallows updates for all attributes _except_ id and enabled -- CREATE TRIGGER deny_test_users_excluding BEFORE UPDATE ON test_users FOR EACH ROW EXECUTE PROCEDURE deny_updates('ALLOW_LIST', id, enabled); -- The following updates should be successfull -- UPDATE test_users SET id=id+1, enabled=false WHERE name='alexk'; UPDATE test_users SET enabled=true; -- The following updates should fail -- UPDATE test_users SET name='stupid', password='simple'; UPDATE test_users SET id=id+1, password='empty' WHERE name='alexk' AND id>2; -- Check if we still can do INSERTs and DELETEs -- -- I guess Devrim has a rather cryptic password... -- INSERT INTO test_users VALUES(20, 'devrim', '!@#23asd~21112A2ss1!', false); DELETE FROM test_users WHERE id<10; -- Check the result -- SELECT * FROM test_users; -- Drop all triggers -- DROP TRIGGER deny_test_users_excluding ON test_users; -- Set trigger on non-existing attribute -- CREATE TRIGGER deny_test_not_exists BEFORE UPDATE ON test_users FOR EACH ROW EXECUTE PROCEDURE deny_updates('ALLOW_LIST', flag); -- Insert should not be affected by the trigger -- INSERT INTO test_users VALUES(120, 'alexk', 'notexists', false); -- Update should fail due to the incorrect trigger column name argument -- UPDATE test_users SET name='stupid', password='simple'; -- Check the result -- SELECT * FROM test_users; -- Finally drop the test relation -- DROP TABLE test_users; -- Check if quoted identifiers are supported -- CREATE TEMP TABLE quoted_test(" id" INTEGER, "a,""text"" in column" TEXT); CREATE TRIGGER deny_quoted_test_id BEFORE UPDATE ON quoted_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('', " id" ); INSERT INTO quoted_test VALUES(1, 'some text'); -- Should be blocked -- UPDATE quoted_test SET " id" = 2; -- Should be allowed -- UPDATE quoted_test SET "a,""text"" in column"='some other text'; -- Check the result -- SELECT * FROM quoted_test; DROP TRIGGER deny_quoted_test_id ON quoted_test; CREATE TRIGGER deny_quoted_test_not_id BEFORE UPDATE ON quoted_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('ALLOW_LIST', " id"); -- Should be allowed -- UPDATE quoted_test SET " id" = 3; -- Should be blocked -- UPDATE quoted_test SET "a,""text"" in column"='some more text'; -- Check the result -- SELECT * FROM quoted_test; DROP TRIGGER deny_quoted_test_not_id on quoted_test; DROP TABLE quoted_test; -- Check if we can allow/disallow updates to all fields at once -- CREATE TEMP TABLE update_all_test(id INTEGER, rank INTEGER, name VARCHAR); CREATE TRIGGER update_all_test_deny BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('ALLOW_LIST'); INSERT INTO update_all_test VALUES(1, 1, 'www.google.com'); INSERT INTO update_all_test VALUES(1, 2, 'www.yahoo.com'); -- Should be denied -- UPDATE update_all_test SET id=3; UPDATE update_all_test SET rank = 3; UPDATE update_all_test SET name='www.live.com'; -- Check the result -- SELECT * FROM update_all_test; DROP TRIGGER update_all_test_deny ON update_all_test; CREATE TRIGGER update_all_test_allow BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates(''); -- Should be allowed -- UPDATE update_all_test SET id=3; UPDATE update_all_test SET rank = 3; UPDATE update_all_test SET name='www.live.com'; -- Check the result -- SELECT * FROM update_all_test; DROP TRIGGER update_all_test_allow ON update_all_test; -- Check if we can handle missing parameters case -- CREATE TRIGGER update_all_test_incorrect BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates(); -- Should be denied -- UPDATE update_all_test SET rank = rank + 1; DROP TRIGGER update_all_test_incorrect ON update_all_test; -- Check for the NULL values -- CREATE TRIGGER update_test_name BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('', name); -- Should be allowed UPDATE update_all_test SET rank = NULL; -- Should be cancelled UPDATE update_all_test SET name=NULL WHERE name = 'www.live.com'; -- Create trigger on rank CREATE TRIGGER update_test_rank BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('', rank); -- Should be cancelled -- UPDATE update_all_test SET rank = 3; -- 'Updating' rank field from NULL to NULL, should be allowed UPDATE update_all_test SET rank = NULL, id=1; -- Check the result -- SELECT *from update_all_test; -- Drop all triggers -- DROP TRIGGER update_test_name ON update_all_test; DROP TRIGGER update_test_rank ON update_all_test; -- Test ONLY_FROM_NULL functionality CREATE TRIGGER update_test_null BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('ONLY_FROM_NULL', rank); -- Should be allowed -- UPDATE update_all_test SET rank = 42; UPDATE update_all_test SET id = NULL; -- Should be blocked -- UPDATE update_all_test SET rank = -42; DROP TRIGGER update_test_null ON update_all_test; CREATE TRIGGER update_test_null BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('ONLY_FROM_NULL,ALLOW_LIST', rank); -- Should be allowed -- UPDATE update_all_test SET id = rank; UPDATE update_all_test SET rank = NULL; -- Should be blocked -- UPDATE update_all_test SET id = 10; -- Check if invalid values of 'allowed' param are rejected -- CREATE TRIGGER update_test_invalid BEFORE UPDATE ON update_all_test FOR EACH ROW EXECUTE PROCEDURE deny_updates('foo', rank); -- Should fail with error message stating that the allowed_arg value is invalid -- UPDATE update_all_test SET rank=rank+1; -- DROP trigger and target table -- DROP TRIGGER update_test_invalid ON update_all_test; DROP TABLE update_all_test; DROP LANGUAGE plperlu CASCADE;