PostgreSQL์˜ ํ–‰ ์ˆ˜์ค€ ๋ณด์•ˆ ๊ตฌํ˜„์— ๊ด€ํ•œ ์—ฐ๊ตฌ

๋ณด์™„์ฑ…์œผ๋กœ๋Š” PostgreSQL ์ €์žฅ ํ•จ์ˆ˜ ์ˆ˜์ค€์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„์— ๊ด€ํ•œ ์—ฐ๊ตฌ ะธ ์ฃผ๋กœ ์ž์„ธํ•œ ๋‹ต๋ณ€์„ ์œ„ํ•ด ์— ๋…ผํ‰.

์ด๋ก ์ ์ธ ๋ถ€๋ถ„์€ ๋ฌธ์„œ์— ์ž˜ ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํฌ์ŠคํŠธ๊ทธ๋ ˆSQL - ํ–‰ ๋ณดํ˜ธ ์ •์ฑ…. ์•„๋ž˜๋Š” ์ž‘์€ ์‹ค์ œ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค. ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ์ž‘์—… - ์‚ญ์ œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆจ๊น๋‹ˆ๋‹ค. ๊ตฌํ˜„ ์ „์šฉ ์Šค์ผ€์น˜ RLS๋ฅผ ์‚ฌ์šฉํ•œ ์—ญํ•  ๋ชจ๋ธ๋ง ๋ณ„๋„๋กœ ์ œ์‹œ๋ฉ๋‹ˆ๋‹ค.

PostgreSQL์˜ ํ–‰ ์ˆ˜์ค€ ๋ณด์•ˆ ๊ตฌํ˜„์— ๊ด€ํ•œ ์—ฐ๊ตฌ

๊ธฐ์‚ฌ์—๋Š” ์ƒˆ๋กœ์šด ๋‚ด์šฉ์ด ์—†์œผ๋ฉฐ ์ˆจ๊ฒจ์ง„ ์˜๋ฏธ๋‚˜ ๋น„๋ฐ€ ์ง€์‹๋„ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ก ์  ์•„์ด๋””์–ด์˜ ์‹ค์ œ ๊ตฌํ˜„์— ๋Œ€ํ•œ ์Šค์ผ€์น˜์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ตฌ๋“ ์ง€ ๊ด€์‹ฌ์ด ์žˆ๋‹ค๋ฉด ์ฝ์–ด๋ณด์„ธ์š”. ๊ด€์‹ฌ์ด ์—†๋‹ค๋ฉด ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

๋ฌธ์ œ ์„ฑ๋ช…

์ฃผ์ œ ์˜์—ญ์„ ๊นŠ์ด ํŒŒ๊ณ ๋“ค์ง€ ์•Š๊ณ  ๊ฐ„๋‹จํžˆ ๋ฌธ์ œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ณต์‹ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํ…Œ์ด๋ธ”์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ”์˜ ํ–‰์€ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œํ•  ์ˆ˜๋Š” ์—†์œผ๋ฏ€๋กœ ์ˆจ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โ€œ์•„๋ฌด ๊ฒƒ๋„ ์‚ญ์ œํ•˜์ง€ ๋ง๊ณ  ์ด๋ฆ„์„ ๋ฐ”๊พธ์„ธ์š”. ์ธํ„ฐ๋„ท์€ ๋ชจ๋“  ๊ฒƒ์„ ์ €์žฅํ•œ๋‹ค"

๊ทธ ๊ณผ์ •์—์„œ ์ด ์—”ํ„ฐํ‹ฐ์™€ ์ž‘๋™ํ•˜๋Š” ๊ธฐ์กด ์ €์žฅ ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ด ๊ฐœ๋…์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ด๋ธ”์—๋Š” ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ญ์ œ๋จ. ๊ทธ๋Ÿฌ๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์†์„ฑ์ด ํฌํ•จ๋œ ํ–‰๋งŒ ๋ณผ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‚ญ์ œ๋จ ๊ฑฐ์ง“ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ๋ฌด์—‡์„ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๊นŒ? ํ–‰ ์ˆ˜์ค€ ๋ณด์•ˆ.

ะ ะตะฐะปะธะทะฐั†ะธั

๋ณ„๋„์˜ ์—ญํ•  ๋ฐ ์Šคํ‚ค๋งˆ ์ƒ์„ฑ

CREATE ROLE repos;
CREATE SCHEMA repos;

๋Œ€์ƒ ํ…Œ์ด๋ธ” ์ƒ์„ฑ

CREATE TABLE repos.file
(
...
is_del BOOLEAN DEFAULT FALSE
);
CREATE SCHEMA repos

์ผœ ํ–‰ ์ˆ˜์ค€ ๋ณด์•ˆ

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)

๋ฌธ์ œ ์„ค๋ช…์—์„œ ์š”๊ตฌ๋˜๋Š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

ํ•ฉ๊ณ„

์ฃผ์ œ๊ฐ€ ํฅ๋ฏธ๋กญ๋‹ค๋ฉด ๋‹ค์Œ ์—ฐ๊ตฌ์—์„œ ํ–‰ ์ˆ˜์ค€ ๋ณด์•ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์—ญํ•  ๊ธฐ๋ฐ˜ ๋ชจ๋ธ์„ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€