LOAD 'chdb_hook';

CREATE TABLE secrets (
    id     INT  PRIMARY KEY,
    name   TEXT NOT NULL,
    secret TEXT NOT NULL
);
INSERT INTO secrets VALUES (1, 'alice', 'hunter2'), (2, 'bob', 'letmein');

CREATE TABLE names (
    id   INT  PRIMARY KEY,
    name TEXT NOT NULL,
    who  TEXT NOT NULL DEFAULT current_user
);

-- Clean up after any previous failed run.
SET client_min_messages = error;
DROP ROLE IF EXISTS chdb_none;
DROP ROLE IF EXISTS chdb_reader;
RESET client_min_messages;
CREATE ROLE chdb_none;
CREATE ROLE chdb_reader;
GRANT SELECT (id, name) ON secrets TO chdb_reader;
GRANT INSERT (id, name) ON names TO chdb_reader;

-- Disable quiet to emit COPY numbers
\set QUIET false

-- Copy through /tmp, which the server can always read and write.
\set names_out file:///tmp/permissions.tmp/names.tsv

-- Copying a server file requires the same role membership as a Postgres COPY.
SET ROLE chdb_reader;
COPY secrets (id, name) TO :'names_out';
COPY names (id, name) FROM :'names_out';
RESET ROLE;
GRANT pg_read_server_files, pg_write_server_files TO chdb_none, chdb_reader;

-- A role without privileges cannot copy the relation.
SET ROLE chdb_none;
COPY secrets TO :'names_out';
COPY secrets FROM :'names_out';

-- Column privileges cover only the copied columns.
SET ROLE chdb_reader;
COPY secrets TO :'names_out';
COPY secrets (id, secret) TO :'names_out';
COPY secrets (id, name) TO :'names_out';

-- The copy runs as the role that ran the COPY.
COPY names (id, name) FROM :'names_out';
RESET ROLE;
SELECT * FROM names ORDER BY id;

-- COPY TO PROGRAM remains Postgres's business.
SET ROLE chdb_reader;
COPY names TO PROGRAM 'file:///bin/cat';
RESET ROLE;

-- chDB copies every row, so row-level security cannot be applied.
ALTER TABLE secrets ENABLE ROW LEVEL SECURITY;
CREATE POLICY own_secret ON secrets FOR SELECT TO chdb_reader USING (name = current_user);
SET ROLE chdb_reader;
COPY secrets (id, name) TO :'names_out';
SET row_security = off;
COPY secrets (id, name) TO :'names_out';
RESET row_security;
RESET ROLE;

-- The owner bypasses row-level security, so exports every row.
COPY secrets TO :'names_out';
CREATE TABLE exported (LIKE secrets);
COPY exported FROM :'names_out';
SELECT * FROM exported ORDER BY id;

-- COPY FROM writes, so a read-only transaction rejects it.
BEGIN READ ONLY;
COPY names FROM :'names_out';
ROLLBACK;

-- The copy runs in this session, so it sees its temporary relations.
CREATE TEMP TABLE tmp_names (id INT, name TEXT);
COPY names (id, name) TO :'names_out';
COPY tmp_names FROM :'names_out';
SELECT * FROM tmp_names ORDER BY id;

-- The copy joins this transaction, so a rollback takes its rows with it.
BEGIN;
COPY tmp_names FROM :'names_out';
SELECT count(*) FROM tmp_names;
ROLLBACK;
SELECT count(*) FROM tmp_names;

DROP TABLE secrets, names, exported;
DROP ROLE chdb_none, chdb_reader;

-- Files belong to the server user, so ignore failure to remove them.
\! rm -rf /tmp/permissions.tmp 2>/dev/null
