Π ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΊ
Π’Π΅ΠΎΡΠ΅ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠ°ΡΡΡ ΠΎΡΠ»ΠΈΡΠ½ΠΎ ΠΎΠΏΠΈΡΠ°Π½Π° Π² Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ
Π ΡΡΠ°ΡΡΠ΅ Π½ΠΈΡΠ΅Π³ΠΎ Π½ΠΎΠ²ΠΎΠ³ΠΎ, Π½Π΅Ρ ΡΠΊΡΡΡΠΎΠ³ΠΎ ΡΠΌΡΡΠ»Π° ΠΈ ΡΠ°ΠΉΠ½ΡΡ Π·Π½Π°Π½ΠΈΠΉ. ΠΡΠΎΡΡΠΎ Π·Π°ΡΠΈΡΠΎΠ²ΠΊΠ° ΠΎ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠ΅ΠΎΡΠ΅ΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΠΈΠ΄Π΅ΠΈ. ΠΡΠ»ΠΈ ΠΊΠΎΠΌΡ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΎ β ΡΠΈΡΠ°ΠΉΡΠ΅. ΠΠΎΠΌΡ Π½Π΅ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΎ β Π½Π΅ ΡΡΠ°ΡΡΡΠ΅ ΡΠ²ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ Π·ΡΡ.
ΠΠΎΡΡΠ°Π½ΠΎΠ²ΠΊΠ° Π·Π°Π΄Π°ΡΠΈ
ΠΠ΅ ΠΏΠΎΠ³ΡΡΠΆΠ°ΡΡΡ Π³Π»ΡΠ±ΠΎΠΊΠΎ Π² ΠΏΡΠ΅Π΄ΠΌΠ΅ΡΠ½ΡΡ ΠΎΠ±Π»Π°ΡΡΡ, ΠΊΡΠ°ΡΠΊΠΎ, Π·Π°Π΄Π°ΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΡΡΠΎΡΠΌΡΠ»ΠΈΡΠΎΠ²Π°ΡΡ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ: ΠΈΠΌΠ΅Π΅ΡΡΡ ΡΠ°Π±Π»ΠΈΡΠ° ΡΠ΅Π°Π»ΠΈΠ·ΡΡΡΠ°Ρ Π½Π΅ΠΊΡΡ Π±ΠΈΠ·Π½Π΅Ρ ΡΡΡΠ½ΠΎΡΡΡ. Π‘ΡΡΠΎΠΊΠΈ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ ΠΌΠΎΠ³ΡΡ ΡΠ΄Π°Π»ΡΡΡΡΡ, Π½ΠΎ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΄Π°Π»ΡΡΡ ΡΡΡΠΎΠΊΠΈ Π½Π΅Π»ΡΠ·Ρ, Π½ΡΠΆΠ½ΠΎ ΠΈΡ ΡΠΊΡΡΠ²Π°ΡΡ.
ΠΠ±ΠΎ ΡΠΊΠ°Π·Π°Π½ΠΎ β Β«ΠΠΈΡΠ΅Π³ΠΎ Π½Π΅ ΡΠ΄Π°Π»ΡΠΉ, ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ΅ΠΈΠΌΠ΅Π½ΠΎΠ²ΡΠ²Π°ΠΉ. ΠΠ½ΡΠ΅ΡΠ½Π΅Ρ Ρ ΡΠ°Π½ΠΈΡ ΠΠ‘ΠΒ»
ΠΠΎΠΏΡΡΠ½ΠΎ, ΠΆΠ΅Π»Π°ΡΠ΅Π»ΡΠ½ΠΎ Π½Π΅ ΠΏΠ΅ΡΠ΅ΠΏΠΈΡΡΠ²Π°ΡΡ ΡΠΆΠ΅ ΠΈΠΌΠ΅ΡΡΠΈΠ΅ΡΡ Ρ ΡΠ°Π½ΠΈΠΌΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠ΅ Ρ Π΄Π°Π½Π½ΠΎΠΉ ΡΡΡΠ½ΠΎΡΡΡΡ.
ΠΠ»Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π°Π½Π½ΠΎΠΉ ΠΊΠΎΠ½ΡΠ΅ΠΏΡΠΈΠΈ, ΡΠ°Π±Π»ΠΈΡΠ° ΠΈΠΌΠ΅Π΅Ρ Π°ΡΡΠΈΠ±ΡΡ is_deleted. ΠΠ°Π»Π΅Π΅ Π²ΡΠ΅ ΠΏΡΠΎΡΡΠΎ β Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΠ΄Π΅Π»Π°ΡΡ ΡΠ°ΠΊ, ΡΡΠΎ Π±Ρ ΠΊΠ»ΠΈΠ΅Π½Ρ ΠΌΠΎΠ³ Π²ΠΈΠ΄Π΅ΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΡΡΡΠΎΠΊΠΈ Π² ΠΊΠΎΡΠΎΡΡΡ Π°ΡΡΠΈΠ±ΡΡ is_deleted Π»ΠΎΠΆΠ΅Π½. ΠΠ»Ρ ΡΠ΅Π³ΠΎ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌ Row Level Security.
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ
Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΡ ΡΠΎΠ»Ρ ΠΈ ΡΡ Π΅ΠΌΡ
CREATE ROLE repos;
CREATE SCHEMA repos;
Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠ΅Π»Π΅Π²ΡΡ ΡΠ°Π±Π»ΠΈΡΡ
CREATE TABLE repos.file
(
...
is_del BOOLEAN DEFAULT FALSE
);
CREATE SCHEMA repos
ΠΠΊΠ»ΡΡΠ°Π΅ΠΌ Row Level Security
ALTER TABLE repos.file ENABLE ROW LEVEL SECURITY ;
CREATE POLICY file_invisible_deleted ON repos.file FOR ALL TO dba_role USING ( NOT is_deleted );
GRANT ALL ON TABLE repos.file to dba_role ;
GRANT USAGE ON SCHEMA repos TO dba_role ;
Π‘Π΅ΡΠ²ΠΈΡΠ½Π°Ρ ΡΡΠ½ΠΊΡΠΈΡ β ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΡΡΡΠΎΠΊΠΈ Π² ΡΠ°Π±Π»ΠΈΡΠ΅
CREATE OR REPLACE repos.delete( curr_id repos.file.id%TYPE)
RETURNS integer AS $$
BEGIN
...
UPDATE repos.file
SET is_del = TRUE
WHERE id = curr_id ;
...
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ΠΠΈΠ·Π½Π΅Ρ ΡΡΠ½ΠΊΡΠΈΡ β ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°
CREATE OR REPLACE business_functions.deleteDoc( doc_for_delete JSON )
RETURNS JSON AS $$
BEGIN
...
PERFORM repos.delete( doc_id ) ;
...
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
Π Π΅Π·ΡΠ»ΡΡΠ°ΡΡ
ΠΠ»ΠΈΠ΅Π½Ρ ΡΠ΄Π°Π»ΡΠ΅Ρ Π΄ΠΎΠΊΡΠΌΠ΅Π½Ρ
SELECT business_functions.delCFile( (SELECT json_build_object( 'CId', 3 )) );
ΠΠΎΡΠ»Π΅ ΡΠ΄Π°Π»Π΅Π½ΠΈΡ, ΠΊΠ»ΠΈΠ΅Π½Ρ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ° Π½Π΅ Π²ΠΈΠ΄ΠΈΡ
SELECT business_functions.getCFile"( (SELECT json_build_object( 'CId', 3 )) ) ;
-----------------
(0 rows)
ΠΠΎ Π² ΠΠ Π΄ΠΎΠΊΡΠΌΠ΅Π½Ρ Π½Π΅ ΡΠ΄Π°Π»Π΅Π½, ΡΠΎΠ»ΡΠΊΠΎ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ Π°ΡΡΠΈΠ±ΡΡ is_del
psql -d my_db
SELECT id, name , is_del FROM repos.file ;
id | name | is_del
--+---------+------------
1 | test_1 | t
(1 row)
Π§ΡΠΎ ΠΈ ΡΡΠ΅Π±ΠΎΠ²Π°Π»ΠΎΡΡ Π² ΠΏΠΎΡΡΠ°Π½ΠΎΠ²ΠΊΠ΅ Π·Π°Π΄Π°ΡΠΈ.
ΠΡΠΎΠ³
ΠΡΠ»ΠΈ ΡΠ΅ΠΌΠ° Π±ΡΠ΄Π΅Ρ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½Π°, Π² ΡΠ»Π΅Π΄ΡΡΡΠ΅ΠΌ ΡΡΡΠ΄Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΠΏΡΠΈΠΌΠ΅Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠΎΠ»Π΅Π²ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΡΠ°Π·Π΄Π΅Π»Π΅Π½ΠΈΡ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ Π΄Π°Π½Π½ΡΠΌ Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Row Level Security.
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com