mirror of https://github.com/citusdata/citus.git
Add CREATE VIEW statement for columnar.storage with security barrier
Add new views for columnar storage: stripe, chunk_group, and chunk with security barrier Refactor columnar views to use OR REPLACE for consistent binding and add missing comments Enhance columnar test helpers with visibility check function and update related queries for improved storage ID retrievalm3hm3t/pg18_columnar_access_temp_after_review
parent
2df9cee5a4
commit
b947c8ce6b
|
|
@ -1,2 +1,44 @@
|
|||
-- citus_columnar--13.2-1--14.0-1
|
||||
-- bump version to 14.0-1
|
||||
|
||||
CREATE OR REPLACE VIEW columnar.storage WITH (security_barrier) AS
|
||||
SELECT c.oid::regclass AS relation,
|
||||
columnar.get_storage_id(c.oid) AS storage_id
|
||||
FROM pg_catalog.pg_class c
|
||||
JOIN pg_catalog.pg_am am ON c.relam = am.oid
|
||||
WHERE am.amname = 'columnar'
|
||||
-- exclude other sessions' temp rels, but keep *my* temp tables
|
||||
AND (c.relpersistence <> 't'
|
||||
OR c.relnamespace = pg_catalog.pg_my_temp_schema())
|
||||
AND pg_catalog.pg_has_role(c.relowner, 'USAGE');
|
||||
COMMENT ON VIEW columnar.storage IS 'Columnar relation ID to storage ID mapping.';
|
||||
GRANT SELECT ON columnar.storage TO PUBLIC;
|
||||
|
||||
-- re-emit dependent views with OR REPLACE so they stay bound cleanly
|
||||
CREATE OR REPLACE VIEW columnar.stripe WITH (security_barrier) AS
|
||||
SELECT relation, storage.storage_id, stripe_num, file_offset, data_length,
|
||||
column_count, chunk_row_count, row_count, chunk_group_count, first_row_number
|
||||
FROM columnar_internal.stripe stripe, columnar.storage storage
|
||||
WHERE stripe.storage_id = storage.storage_id;
|
||||
COMMENT ON VIEW columnar.stripe
|
||||
IS 'Columnar stripe information for tables on which the current user has ownership privileges.';
|
||||
GRANT SELECT ON columnar.stripe TO PUBLIC;
|
||||
|
||||
CREATE OR REPLACE VIEW columnar.chunk_group WITH (security_barrier) AS
|
||||
SELECT relation, storage.storage_id, stripe_num, chunk_group_num, row_count
|
||||
FROM columnar_internal.chunk_group cg, columnar.storage storage
|
||||
WHERE cg.storage_id = storage.storage_id;
|
||||
COMMENT ON VIEW columnar.chunk_group
|
||||
IS 'Columnar chunk group information for tables on which the current user has ownership privileges.';
|
||||
GRANT SELECT ON columnar.chunk_group TO PUBLIC;
|
||||
|
||||
CREATE OR REPLACE VIEW columnar.chunk WITH (security_barrier) AS
|
||||
SELECT relation, storage.storage_id, stripe_num, attr_num, chunk_group_num,
|
||||
minimum_value, maximum_value, value_stream_offset, value_stream_length,
|
||||
exists_stream_offset, exists_stream_length, value_compression_type,
|
||||
value_compression_level, value_decompressed_length, value_count
|
||||
FROM columnar_internal.chunk chunk, columnar.storage storage
|
||||
WHERE chunk.storage_id = storage.storage_id;
|
||||
COMMENT ON VIEW columnar.chunk
|
||||
IS 'Columnar chunk information for tables on which the current user has ownership privileges.';
|
||||
GRANT SELECT ON columnar.chunk TO PUBLIC;
|
||||
|
|
|
|||
|
|
@ -214,8 +214,8 @@ SELECT COUNT(*) FROM columnar_temp WHERE i < 5;
|
|||
4
|
||||
(1 row)
|
||||
|
||||
SELECT columnar.get_storage_id(oid) AS columnar_temp_storage_id
|
||||
FROM pg_class WHERE relname='columnar_temp' \gset
|
||||
SELECT COALESCE(columnar_test_helpers.get_storage_id_if_visible('columnar_temp'::regclass), 0)
|
||||
AS columnar_temp_storage_id \gset
|
||||
BEGIN;
|
||||
DROP TABLE columnar_temp;
|
||||
-- show that we drop stripes properly
|
||||
|
|
|
|||
|
|
@ -11,10 +11,19 @@ $$ LANGUAGE SQL;
|
|||
INSERT INTO t2 SELECT i, f(i) FROM generate_series(1, 5) i;
|
||||
-- there are no subtransactions, so above statement should batch
|
||||
-- INSERTs inside the UDF and create on stripe per table.
|
||||
SELECT relname, count(*) FROM columnar.stripe a, pg_class b
|
||||
WHERE columnar.get_storage_id(b.oid)=a.storage_id AND relname IN ('t1', 't2')
|
||||
GROUP BY relname
|
||||
ORDER BY relname;
|
||||
WITH rels(rel) AS (
|
||||
VALUES ('t1'::regclass), ('t2'::regclass)
|
||||
),
|
||||
sids AS (
|
||||
SELECT rel, columnar.get_storage_id(rel) AS sid
|
||||
FROM rels
|
||||
)
|
||||
SELECT c.relname, COUNT(*) AS count
|
||||
FROM columnar_internal.stripe st
|
||||
JOIN sids s ON st.storage_id = s.sid
|
||||
JOIN pg_catalog.pg_class c ON c.oid = s.rel
|
||||
GROUP BY c.relname
|
||||
ORDER BY c.relname;
|
||||
relname | count
|
||||
---------------------------------------------------------------------
|
||||
t1 | 1
|
||||
|
|
|
|||
|
|
@ -146,3 +146,15 @@ BEGIN
|
|||
RETURN NEXT;
|
||||
END LOOP;
|
||||
END; $$ language plpgsql;
|
||||
CREATE OR REPLACE FUNCTION get_storage_id_if_visible(rel regclass)
|
||||
RETURNS bigint
|
||||
LANGUAGE sql STABLE AS $$
|
||||
SELECT CASE
|
||||
WHEN c.relpersistence = 't'
|
||||
AND c.relnamespace <> pg_catalog.pg_my_temp_schema()
|
||||
THEN NULL -- other session’s temp → don’t touch
|
||||
ELSE columnar.get_storage_id(c.oid)
|
||||
END
|
||||
FROM pg_catalog.pg_class c
|
||||
WHERE c.oid = $1::oid
|
||||
$$;
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ INSERT INTO columnar_temp SELECT i FROM generate_series(1,5) i;
|
|||
-- test basic select
|
||||
SELECT COUNT(*) FROM columnar_temp WHERE i < 5;
|
||||
|
||||
SELECT columnar.get_storage_id(oid) AS columnar_temp_storage_id
|
||||
FROM pg_class WHERE relname='columnar_temp' \gset
|
||||
SELECT COALESCE(columnar_test_helpers.get_storage_id_if_visible('columnar_temp'::regclass), 0)
|
||||
AS columnar_temp_storage_id \gset
|
||||
|
||||
BEGIN;
|
||||
DROP TABLE columnar_temp;
|
||||
|
|
|
|||
|
|
@ -15,10 +15,20 @@ INSERT INTO t2 SELECT i, f(i) FROM generate_series(1, 5) i;
|
|||
|
||||
-- there are no subtransactions, so above statement should batch
|
||||
-- INSERTs inside the UDF and create on stripe per table.
|
||||
SELECT relname, count(*) FROM columnar.stripe a, pg_class b
|
||||
WHERE columnar.get_storage_id(b.oid)=a.storage_id AND relname IN ('t1', 't2')
|
||||
GROUP BY relname
|
||||
ORDER BY relname;
|
||||
WITH rels(rel) AS (
|
||||
VALUES ('t1'::regclass), ('t2'::regclass)
|
||||
),
|
||||
sids AS (
|
||||
SELECT rel, columnar.get_storage_id(rel) AS sid
|
||||
FROM rels
|
||||
)
|
||||
SELECT c.relname, COUNT(*) AS count
|
||||
FROM columnar_internal.stripe st
|
||||
JOIN sids s ON st.storage_id = s.sid
|
||||
JOIN pg_catalog.pg_class c ON c.oid = s.rel
|
||||
GROUP BY c.relname
|
||||
ORDER BY c.relname;
|
||||
|
||||
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
|
|
|
|||
|
|
@ -158,3 +158,16 @@ BEGIN
|
|||
RETURN NEXT;
|
||||
END LOOP;
|
||||
END; $$ language plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_storage_id_if_visible(rel regclass)
|
||||
RETURNS bigint
|
||||
LANGUAGE sql STABLE AS $$
|
||||
SELECT CASE
|
||||
WHEN c.relpersistence = 't'
|
||||
AND c.relnamespace <> pg_catalog.pg_my_temp_schema()
|
||||
THEN NULL -- other session’s temp → don’t touch
|
||||
ELSE columnar.get_storage_id(c.oid)
|
||||
END
|
||||
FROM pg_catalog.pg_class c
|
||||
WHERE c.oid = $1::oid
|
||||
$$;
|
||||
|
|
|
|||
Loading…
Reference in New Issue